Search code examples
c#-4.0tddrhino-mocks-3.5

RhinoMocks AssertWasCalled throws Exception


I am new to TDD and RhinoMocks.

I am trying to test AssertWasCalled but having problems. The constructor to my test is as follows:

    public AccountControllerTests()
    {
        _webAuthenticator = MockRepository.GenerateMock<IWebAuthenticator>();
    }

And my test is like this:

    [TestMethod]
    public void AccountControllerCallsWebAuthenticator_CreateSignInTicketForGoodLoginCredentials()
    {
        const string username = "good-username";
        const string password = "good-password";

        var model = new LoginModel { Username = username, Password = password };

        _webAuthenticator.Stub(w => w.Authenticate(username, password)).Return(true);

        var mockHttpContextBase = MockRepository.GenerateMock<HttpContextBase>();

        var accountController = new AccountController(_webAuthenticator);

        accountController.Login(model);

        _webAuthenticator.AssertWasCalled(x => x.CreateSignInTicket(mockHttpContextBase, username));
    }

The error I get is:

Test method Paxium.Music.WebUI.Tests.Controllers.AccountControllerTests.AccountControllerCallsWebAuthenticator_CreateSignInTicketForGoodLoginCredentials threw exception: Rhino.Mocks.Exceptions.ExpectationViolationException: IWebAuthenticator.CreateSignInTicket(Castle.Proxies.HttpContextBaseProxy7f274f09b6124e6da32d96dc6d3fface, "good-username"); Expected #1, Actual #0.

I have now changed my code as below - Before and after code:

Before:

public class AccountController : Controller
{
    private readonly IWebAuthenticator _webAuthenticator;

    public AccountController(IWebAuthenticator webAuthenticator)
    {
        _webAuthenticator = webAuthenticator;
    }

    [HttpGet]
    public ActionResult Login()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Login(LoginModel model)
    {
        if (ModelState.IsValid)
        {
            if (_webAuthenticator.Authenticate(model.Username, model.Password))
            {
                _webAuthenticator.CreateSignInTicket(HttpContext, model.Username);

                return RedirectToAction("Index", "Home");
            }

            return View(model);
        }

        return View(model);
    }
}

After:

public class AccountController : Controller
{
    private readonly IWebAuthenticator _webAuthenticator;
    private readonly HttpContextBase _contextBase;

    public AccountController()
    {

    }

    public AccountController(IWebAuthenticator webAuthenticator, HttpContextBase contextBase)
    {
        _webAuthenticator = webAuthenticator;
        _contextBase = contextBase;
    }

    [HttpGet]
    public ActionResult Login()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Login(LoginModel model)
    {
        if (ModelState.IsValid)
        {
            if (_webAuthenticator.Authenticate(model.Username, model.Password))
            {
                _webAuthenticator.CreateSignInTicket(_contextBase, model.Username);

                return RedirectToAction("Index", "Home");
            }

            return View(model);
        }

        return View(model);
    }
}

My tests now pass. How I inject in the contextBase though when my controller is used for real?? I am using StructureMap.


Solution

  • The error message you are receiving indicates that the Assert failed, i.e. the webAuthenticator object was not called with those specific arguments (hence expected #1, actual #0 exception message).

    From the limited context you provide, I suspect that the fake instance of the HttpContextBase (mockHttpContextBase) in your test is not the same object that's being passed to the webAuthenticator from your production code.

    There's two ways you can go about this: make the assert less strict or make sure the production code uses the fake http context object. If you don't care which instance of HttpContext gets passed to the webAuthenticator in this test, you can use argument matchers (Rhinomocks calls them argument constraints). In your case, this would turn out something like this:

    _webAuthenticator.AssertWasCalled(x => x.CreateSignInTicket(Arg<HttpContextBase>.Is.Anything, Arg<string>.Is.Equal(username)));