I have a test where I’m mocking 2 service calls that get called in a controller. The return value of the first call (a User POCO) is used to call the second. The problem is that it doesn’t seem to be matching the second because it keeps returning null. If I change the service to return a string instead of the User object, it works fine.
Test:
[Test]
public void GivenExternalReturnUrl_ReturnsHomePage()
{
var model = new Login
{
Username = "user1",
Password = "password1",
ReturnUrl = "http://google.com"
};
UserService.Setup(x => x.ValidateUser(model.Username, model.Password)).Returns(User);
var cookie = new HttpCookie("test");
UserService.Setup(x => x.BuildLoginCookie(User, model.RememberMe)).Returns(cookie);
var result = Controller.Login(model) as RedirectToRouteResult;
result.Should().Not.Be.Null();
result.RouteValues["controller"].Should().Equal("Home");
result.RouteValues["action"].Should().Equal("Index");
UserService.Verify(x => x.BuildLoginCookie(User, model.RememberMe), Times.Once());
}
BuildLoginCookie is returning null instead of the cookie object.
Action that it’s testing:
[HttpPost]
public ActionResult Login(Login model)
{
if (ModelState.IsValid)
{
var user = _userService.ValidateUser(model.Username, model.Password);
if (user != null)
{
var cookie = _userService.BuildLoginCookie(user, model.RememberMe);
Response.Cookies.Add(cookie);
if (Url.IsLocalUrl(model.ReturnUrl))
return Redirect(model.ReturnUrl);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("InvalidCredentials", "The user name or password provided is incorrect.");
}
// If we got this far, something failed, redisplay form
model.Password = null; //clear the password so they have to re-enter it
return View(model);
}
What do I need to do so that Moq will match that second call and return the value I’m telling it to return?
The problem is with your property
public UserWithRolesPermissions User { get { new UserWithRolesPermissions(); } }Every time you call it, it creates a new instance, hence the two references to it are each receiving a new instance, which are not equal. Therefore the calls to setup will not match the invocations.
If you changed your code to use a single instance, it should work fine.
Another option would be to avoid doing comparison of the instances, and just match on a property.