I'm using Rhino Mocks to write my Unit Tests and I'd like to use Assert.WasCalled functionality, but I'm keep getting an error.
My help method used by a bunch of tests:
Private Function CreateSecurityTicketHelper(userName As String, validFrom As DateTime, validTo As DateTime) As ISecurityTicket
' Prepare a mock object for ITicketingDataManager interface
Dim dataManagerMock = MockRepository.GenerateMock(Of ITicketingDataManager)()
' Prepare a mock function for ITicketingDataManager.InitializeNewTicket(string, string)
Dim returnSecurityTicket As Func(Of String, String, ISecurityTicket) = Function(u, k) New SecurityTicketEntity() With {.UserName = u, .Key = k}
dataManagerMock.Stub(Function(x) x.InitializeNewTicket(Nothing, Nothing)).IgnoreArguments().Do(returnSecurityTicket)
' Create new TicketingManager instance
Dim ticketingManager = New TicketingManager(dataManagerMock)
' Try creating new security ticket
Dim ticket = ticketingManager.CreateSecurityTicket(userName, validFrom, validTo)
' Check if proper ITicketingDataManager method was invoked
dataManagerMock.AssertWasCalled(Sub(x) x.InitializeNewTicket(Nothing, Nothing), Sub(z) z.Repeat.Once())
' Return the ticket
Return ticketingManager.CreateSecurityTicket(userName, validFrom, validTo)
End Function
I can debug that method and all goes right until AssertWasCalled method is called, when I'm getting following exception:
Test method
Authentication.UnitTests.TicketingManagerTests.CreateSecurityTicket_ValidUserNameAndKey_TicketIsCreated
threw exception:
Rhino.Mocks.Exceptions.ExpectationViolationException:
ITicketingDataManager.InitializeNewTicket(null, null); Expected #1,
Actual #0.
Your assertion says that InitializeNewTicket() method should be called once with arguments (Nothing, Nothing).
If this method is being called with some another arguments then assertion fails.
You have to rewrite assertion to either A) accept any arguments or B) specify correct arguments.
See examples below.
Few notes about examples:
1. Ufortunatelly I'm not good in VB syntax so providing examples in C#.
2. It is not mentioned in question which parameters type has method InitializeNewTicket() so for example I assume it has String parameters.
To accept any parameters in assertion:
dataManagerMock.AssertWasCalled(
x => x.InitializeNewTicket(Arg<String>.Is.Anything, Arg<String>.Is.Anything),
z => z.Repeat.Once());
To specify expected arguments (e.g. expected1, expected2):
dataManagerMock.AssertWasCalled(
x => x.InitializeNewTicket(Arg<String>.Is.Equal(expected1), Arg<String>.Is.Equal(expected2)),
z => z.Repeat.Once());
Hope that explains the reason of your issue and helps to solve :).
Related
Let's define 2 classes
A.gd
class_name A
var v = null
func _init(v_):
v = v_
B.gd
class_name B
var v = null
Now, when I try to use str2var/var2str, this is what I get
var a = A.new("aaa")
var b = B.new()
b.v = "bbb"
printt("var2str(a):", var2str(a))
printt("var2str(b):", var2str(b))
printt ("var2str(str2var(var2str(a))):", var2str(str2var(var2str(a))))
printt ("var2str(str2var(var2str(b))):", var2str(str2var(var2str(b))))
Output:
var2str(a): Object(Reference,"script":Resource( "res://Scripts/AI/A.gd"),"v":"aaa")
var2str(b): Object(Reference,"script":Resource( "res://Scripts/AI/B.gd"),"v":"bbb")
var2str(str2var(var2str(a))): Object(Reference,"script":null)
var2str(str2var(var2str(b))): Object(Reference,"script":Resource( "res://Scripts/AI/B.gd"),"v":"bbb")
Why is str2var(a) not working?
How should I fix it?
The Solution
Fix it by making the parameter optional, for example:
class_name A
var v = null
func _init(v_ = null):
v = v_
With that there is no error. I get this output:
var2str(a): Object(Reference,"script":Resource( "res://A.gd"),"v":"aaa")
var2str(b): Object(Reference,"script":Resource( "res://B.gd"),"v":"bbb")
var2str(str2var(var2str(a))): Object(Reference,"script":Resource( "res://A.gd"),"v":"aaa")
var2str(str2var(var2str(b))): Object(Reference,"script":Resource( "res://B.gd"),"v":"bbb")
The problem
For abstract, str2var will not pass any arguments to _init. It would not know what to pass anyway.
The rest of the answer is the process of confirming that str2var will result in calling _init with no argument.
When I try your code I get this error:
E 0:00:00.630 _create_instance: Condition "r_error.error != Variant::CallError::CALL_OK" is true. Returned: __null
<C++ Source> modules/gdscript/gdscript.cpp:121 # _create_instance()
<Stack Trace> main.gd:12 # _ready()
We can find the line that throws the error in _create_instance by looking at the source.
Sadly that does not give me much information. So, I decided to search how str2var is implemented.
We find it inside GDScriptFunctions::call, here. Which calls VariantParser::parse, which calls VariantParser::parse_value. We are interested in the case of an "Object" (here). And that results in a call to ClassDB::instance(type). There type will be "Reference", and then it procedes to set all properties as they come. Being the first one "script":Resource("res://A.gd").
When we set the script (here), it will result in a call to GDScript::instance_create. Which calls GDScript::_create_instance (here):
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error)
With no argument for _init (The NULL is the argument array, and 0 is the number of arguments). This is the signature for GDScript::_create_instance:
GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error)
Of course, initializer->call(instance, p_args, p_argcount, r_error); fails, because _init requires an argument. And we find the line that throws the error further down. Note: initializer is created while parsing the script.
I found this SQLHelper online that I would like to run a SQL query with.
But the helper wants an list instead of an string.
and I cannot seem to figure out how to make the executeNonQuery to work.
type SqlHelper (connection) =
let exec bind parametres query =
use conn = new SqlConnection (connection)
conn.Open()
use cmd = new SqlCommand (query, conn)
parametres |> List.iteri (fun i p ->
cmd.Parameters.AddWithValue(sprintf "#p%d" i, box p) |> ignore)
bind cmd
member __.Execute = exec <| fun c -> c.ExecuteNonQuery() |> ignore
member __.Scalar = exec <| fun c -> c.ExecuteScalar()
member __.Read f = exec <| fun c -> [ let read = c.ExecuteReader()
while read.Read() do
yield f read ]
let sql = new SqlHelper (connectionString)
The query I have is for dopping the tables
and I'm trying to execute like this.
let emptyDb =
let query =
"SET NOCOUNT ON
DROP TABLE IF EXISTS #STUFF
...
...
END"
sql.Execute [query ]
This compiles, but nothing happens when I execute it.
Any ideas?
Thanks in advance
Edit: sql.Read function works perfect
let GetToken Id=
sql.Read (fun r -> { token = unbox r.[0] })
[Id;]
"SELECT Token
FROM [dbo].[Token]
WHERE id= 0"
GetToken "1337"
You are not providing enough parameters for sql.Execute.
Look closely:
exec takes three parameters - bind, parametres (btw, typo), and query
In the body of Execute you give it one parameter - bind
Therefore, the result of Execute is a function that still expects the other two parameters - parametres and query
But when you're calling sql.Execute, you're only giving it one parameter - [query], which will end up bound to parametres
Therefore, the result of calling sql.Execute [query] is yet another function, which still expects the final parameter to be provided before its body will be executed. In fact, if you pay close attention to compiler warnings, you will see that the compiler actually tells you as much:
This expression is a function value, i.e. is missing arguments. Its type is ...
To fix, provide the correct parameters. Judging by the little piece of your query that I can see, I assume that it's not supposed to have any parametres, so I'll put an empty list there:
sql.Execute [] query
I have a table that holds links to websites about particular theaters. I want to retrieve the first link for a given theater. My code to set the variable:
Dim link As String = TheaterLinks.Where(Function(x) x.TheaterID = TheaterID).FirstOrDefault().Link
If there are no results (some theaters won't have any links), then I get:
Object reference not set to an instance of an object.
How do I do this? I tried:
Dim link As String = Links.Where(Function(x) x.TheaterID = TheaterID.DefaultIfEmpty().First().Link
But I can't figure out what to put inside DefaultIfEmpty(). I tried DefaultIfEmpty("") and DefaultIfEmpty(blankstringvariable) but then I get:
Value of type 'String' cannot be converted to type 'TheaterLink'.
The problem is that FirstOrDefault() is allowed to return null, in which case accessing Link property would throw an exception.
If you use VB.NET 14, add question mark for automatic null checking:
Dim link As String = TheaterLinks.Where(Function(x) x.TheaterID = TheaterID).FirstOrDefault()?.Link
(see ?.Link instead of .Link)
Otherwise, do it in two stages: first, get the object using FirstOrDefault, then null-check it manually with an If statement.
For my original example, I just had to add a question mark:
Dim link As String = Links.Where(Function(x) x.ID = id).FirstOrDefault()?.Link
I tried doing this in my model and got a "Nullable object must have a value" error, so I did the two-stage approach:
Dim eventDate = Events.Where(Function(x) x.ID = id).FirstOrDefault()?.EventDate
If eventDate.HasValue Then
'some code
Else
'some code
End If
I have the following Class
local PROGRESS = {}
PROGRESS.__index = function(self,key)
if key~="__group" and self.__group[key] then
return self.__group[key]
else
return rawget(self,key)
end
end
What this does is when You access table[key] it performs a lookup in table.__group (which is an object of another class) and returns table.__group[key] ,if it is not nil.
Now I am trying to do the same for member functions.
i.e If I call table:key() a lookup must be performed in table.__group and if the function is present, then table.__group:key() should be called.
How do I accomplish this?
I tried to do this.
local PROGRESS = {}
PROGRESS.__index = function(self,key)
if key~="__group" and self.__group[key] then
local val = self.__group[key]
if type(val) == "function" then
self.__group:val()
return function() end
end
return self.__group[key]
else
return rawget(self,key)
end
end
But there are 2 things wrong here.
I am unable to retrieve the original function's arguments
Event if I just ACCESS table[key].function without calling it, the function will be called
And I've got the feeling that I am trying to complicate things and the solution is way simpler.
Any help is appreciated.
UPDATE
#Mud
The problem with the original code is that the object passed as 'self' to the member function is an object of the new class. Not of the old class.
Consider this code
GROUP_CLASS = {}
GROUP_CLASS.__index = GROUP_CLASS
function GROUP_CLASS:showSum (a,b) print(self);print(a + b) end
group_object = setmetatable({},GROUP_CLASS)
group_object:showSum(1,2)
local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key,value)
if key~="__group" and self.__group[key] then
return self.__group[key]
else
return rawget(self,key)
end
end
progress_object = setmetatable( {__group = group_object} , PROGRESS_CLASS)
progress_object:showSum(3,3)
--progress_object is passed as first argument to showSum. But i need group_object to be passed
In the above code, When progress_object:showSum(3,3) is called,
is it possible to pass group_object (or in other words progress_object.__group) as self instead of progress_object.
Hope that makes sense.
Response to updated post:
progress_object is passed as first argument to showSum. But i need group_object to be passed
If you're going to ignore the state of the object a method is called on, and substitute the state of some other object, why is it even a method on that object? That's like overriding the addition operator to do multiplication, a recipe for confusion.
In other words, you want this:
progress_object:method("foo")
To resolve, via bizarre internal machinery, into this:
group_object:method("foo")
Why not skip a step and just make the latter call?
If you must, you could achieve this by returning a proxy for the method which replaces self with __group
local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key)
local groupval = self.__group[key]
if key == '__group' or not groupval then
return rawget(self,key)
elseif type(groupval) ~= 'function' then
return groupval
else
return function(...)
if self == ... then -- method call
-- replace self argument with __group
return groupval(self.__group,select(2,...))
else
return groupval(...)
end
end
end
end
Response to original post:
How I am trying to do the same for member functions. i.e If I call table:key() a lookup must be performed in table.__group and if the function is present, then table.__group:key() should be called.
How do I accomplish this?
Do nothing. Your original code handles this.
Lua doesn't know what a "member function" is. A member is a member (i.e. an element in a table), and whether the value of that member is a function is irrelevant.
Remember:
obj:method(a,b,c) is exactly equivalent to obj.method(obj,a,b,c)
obj.method is exactly equivalent to obj["method"].
Your code already resolves obj["method"] into obj.__group["method"]
So you're done.
For instance, say we have:
group = {}
function group:showSum (a,b) print(a + b) end
function group:showProduct(a,b) print(a * b) end
Using your first code, we can write:
foo = setmetatable({__group = group}, PROGRESS)
foo:showSum(3,3) -- 6
foo:showProduct(3,3) -- 9
That's it.
Now, as long as we're here, let's look at what your second function is doing:
local val = self.__group[key]
if type(val) == "function" then
self.__group:val()
return function() end
end
First you grab the function value from __group. At this point you're done. Simply return that value, and the caller is going to call that value (i.e. (...)). Instead, you call __group["val"] which is likely a totally different function from __group[key] (unless key=="val"), then you pass the caller a function which does nothing.
I'm getting this error from Moq via NUnit, and it doesn't make much in the way of sense to me.
"Expected invocation on the mock at least once, but was never performed: x => x.DeleteItem(.$VB$Local_item)"
"at Moq.Mock.ThrowVerifyException(MethodCall expected, IEnumerable1 setups, IEnumerable1 actualCalls, Expression expression, Times times, Int32 callCount)
at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
at Moq.Mock.Verify[T](Mock mock, Expression1 expression, Times times, String failMessage)
at Moq.Mock1.Verify(Expression`1 expression)
at PeekABookEditor.UnitTests.ItemBrowsing.Can_Delete_Item() in C:\Projects\MyProject\MyProject.UnitTests\Tests\ItemBrowsing.vb:line 167"
Very similar code works well in C#, so the error might be minor and syntactical on my part.
Here's my code:
<Test()> _
Public Sub Can_Delete_Item()
'Arrange: Given a repository containing some item...
Dim mockRepository = New Mock(Of IItemsRepository)()
Dim item As New Item With {.ItemID = "24", .Title = "i24"}
mockRepository.Setup(Function(x) x.Items).Returns(New Item() {item}.AsQueryable())
'Act ... when the user tries to delete that product
Dim controller = New ItemsController(mockRepository.Object)
Dim result = controller.Delete(24)
'Assert ... then it's deleted, and the user sees a confirmation
mockRepository.Verify(Sub(x) x.DeleteItem(item))
result.ShouldBeRedirectionTo(New With {Key .action = "List"})
Assert.AreEqual(DirectCast(controller.TempData("message"), String), "i24 was deleted")
End Sub
The guilty line appears to be "mockRepository.Verify(Sub(x) x.DeleteItem(item))"
Any thoughts on how to fix this?
Working C# code isn't the exact same, but here it is:
[Test]
public void Can_Delete_Product()
{
// Arrange: Given a repository containing some product...
var mockRepository = new Mock<IProductsRepository>();
var product = new Product { ProductID = 24, Name = "P24"};
mockRepository.Setup(x => x.Products).Returns(
new[] { product }.AsQueryable()
);
// Act: ... when the user tries to delete that product
var controller = new AdminController(mockRepository.Object);
var result = controller.Delete(24);
// Assert: ... then it's deleted, and the user sees a confirmation
mockRepository.Verify(x => x.DeleteProduct(product));
result.ShouldBeRedirectionTo(new { action = "Index" });
controller.TempData["message"].ShouldEqual("P24 was deleted");
}
In your VB test method, you create Item with a string ItemID = "24", but you call the controller.Delete method with an integer value of 24.
Check your controller code and see if the type discrepancy results in the item not being identified correctly, so either DeleteItem is not called at all, or is called with a different Item.