tags:

views:

43

answers:

1

I have a function that updates a user in the asp.net membership provider.

<AcceptVerbs(HttpVerbs.Post)>
Public Function EnableUser(ByVal id As String) As JsonResult
  Dim usr As StargatePortalUser = _membershipService.GetUser(id, Nothing)
  usr.IsApproved = True
  _membershipService.UpdateUser(usr)
  Dim response As New AjaxResponse(usr.UserName)
  Return Json(response)
End Function

I am trying to test this function to ensure the IsApproved property is set correctly

<TestMethod()>
Public Sub Service_Can_Enable_A_User_Account()
  ' Arrange
  Dim usr As New Mock(Of MembershipUser)
  usr.SetupProperty(Function(u) u.IsApproved)

  _membershipService.Setup(Function(m) m.GetUser(It.IsAny(Of String), It.IsAny(Of Boolean))).Returns(usr.Object)

  Dim target As New UsersController(_membershipService.Object)
  target.ControllerContext = New ControllerContext(FakeAuthenticatedHttpContext("testuser", String.Empty, True, True, False), New RouteData, target)

  ' Act
  Dim actual As JsonResult = target.EnableUser("userId")

  ' Assert
  Assert.IsTrue(DirectCast(actual.Data, AjaxResponse).Success)
  _membershipService.Verify(Sub(m) m.UpdateUser(It.IsAny(Of MembershipUser)), Times.Once)
  usr.Verify(Function(u) u.IsApproved = True)
End Sub

When I try to verify that the IsApproved property has been set to True an exception is returned:

System.ArgumentException: Expression is not a method invocation: u => (u.IsApproved == True)

There are so few examples of using Moq in VB that I can't figure this out, any help would be appreciated.

This is an ASP.NET MVC2 app in VB.NET 10 (.NET 4.0)

EDIT:

Ok, turns out it's not quite so straight forward in VB.

usr.Verify(Function(u) u.IsApproved = True)

needs to be

usr.VerifySet(Function(u) InlineAssignHelper(u.IsApproved, True))

and you need to add the following function:

Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
  target = value
  Return value
End Function

FURTHER EDIT:

Thinking around the problem I arrived at a more simple solution. I changed

Dim usr As New Mock(Of MembershipUser)
usr.SetupProperty(Function(u) u.IsApproved)
_membershipService.Setup(Function(m) m.GetUser(It.IsAny(Of String), It.IsAny(Of Boolean))).Returns(usr.Object)

for

Dim usr As New Mock(Of MembershipUser)
usr.SetupProperty(Function(u) u.IsApproved)
Dim usrObj = usr.Object
_membershipService.Setup(Function(m) m.GetUser(It.IsAny(Of String), It.IsAny(Of Boolean))).Returns(usrObj)

and then can replace

usr.VerifySet(Function(u) InlineAssignHelper(u.IsApproved, True))

with the more straightforward

Assert.IsTrue(usrOb.IsApproved)

Sometimes I just don't see the simple solution :)

+1  A: 

You want to use the following (from http://code.google.com/p/moq/wiki/QuickStart):

// or verify the setter directly mock.VerifySet(foo => foo.Name = "foo");

Right now the thing that you're feeding in is a comparison rather than an assignment, so even if Moq did process the statement without an exception, it would still not be Doing What You Mean.

Ruben Bartelink
Ok, changed usr.Verify(Function(u) u.IsApproved = True) to usr.VerifySet(Function(u) u.IsApproved = True). Exception has changed slightly to 'System.ArgumentException: Expression is not a property setter invocation.'
Nick
Hmm, running the C# through a converter gives me mock.VerifySet(Function(foo) InlineAssignHelper(foo.Name, "foo"))I really wish Moq had some documentation in VB.
Nick
@Nick: Is `IsApproved` a Property ? The `SetupSet` stuff is specifically for that. In other words, in order to be able to mock/stub the setting of a value, it needs to be a `virtual` (cant remember what VB calls that!) method (which the setter part of a Property is). There is no neat way to do this in C# either (I'd suggest that if the setting is important enough to be able to stub it should be exposed as a property rather than a raw assingment in the first place). I may not have read (rewad: I ahve not read) your specific code sufficiently for me to be totally correct but I assume you get it
Ruben Bartelink
Yeah, IsApproved is a property on MembershipUser. I came up with a more simple solution (see above) although it was nice to get the complex solution working as well :)
Nick
@Nick: Simple solutions FTW. In general I think as the switch over point between asserts vs mock verification in this case being when it's on an object other than my main object under test. I'd rarely have a public protocol of this nature exposed as a setter (i.e., I'd have a MarkApproved). But obviously YMMV - for all I know you dont even own the class we're talking about.
Ruben Bartelink