views:

952

answers:

2

Hi there,

I have a couple of ActionMethods that queries the Controller.User for its role like this

    Boolean         isAdmin   = User.IsInRole("admin");

acting conveniently on that condition.

I'm starting to make tests for these methods with code like this

[TestMethod]
public void HomeController_Index_Should_Return_Non_Null_ViewPage()
{
    HomeController   controller  = new HomePostController();

    ActionResult     index       = controller.Index();

    Assert.IsNotNull(index);
}

and that Test Fails because Controller.User is not set. Any idea?

+7  A: 

You need to Mock the ControllerContext, HttpContextBase and finally IPrincipal to mock the user property on Controller. Using Moq (v2) something along the following lines should work.

    [TestMethod]
    public void HomeControllerReturnsIndexViewWhenUserIsAdmin() {
        var homeController = new HomeController();

        var userMock = new Mock<IPrincipal>();
        userMock.Expect(p => p.IsInRole("admin")).Returns(true);

        var contextMock = new Mock<HttpContextBase>();
        contextMock.ExpectGet(ctx => ctx.User)
                   .Returns(userMock.Object);

        var controllerContextMock = new Mock<ControllerContext>();
        controllerContextMock.ExpectGet(con => con.HttpContext)
                             .Returns(contextMock.Object);

        homeController.ControllerContext = controllerContextMock.Object;
        var result = homeController.Index();
        userMock.Verify(p => p.IsInRole("admin"));
        Assert.AreEqual(((ViewResult)result).ViewName, "Index");
    }

Testing the behaviour when the user isn't an admin is as simple as changing the expectation set on the userMock object to return false.

sighohwell
A: 

Great sighohwell, this helped me a lot but I found a couple of issues which I write as a response because of its length.

  1. I had instaled moq 2.0 and ExpectGet is supported from version 2.5, as well as Verify(...).
  2. I found here versions 2.6 and 3.1, installed 2.6 and got the following error.

    Warning: Test Run deployment issue: The assembly or module 'MySql.Data' directly or indirectly referenced by the test container 'c:\users\eugenio miró\dev\projects\yyy\xx.trunk\xxtests\bin\debug\xxtests.dll' was not found. Warning: Test Run deployment issue: The assembly or module 'Microsoft.Practices.EnterpriseLibrary.Data' directly or indirectly referenced by the test container 'c:\users\eugenio miró\dev\projects\yyy\xx.trunk\xxtests\bin\debug\xxtests.dll' was not found.

I dont have those references so I suspect moq.dll has them. Did you have to recompile to use it without MySql.Data or EnterpriseLibrary?

EDIT:

Ok, Installed 3.1 and it made it. I had to change 'Expect' to 'Setup' and 'ExpectGet' to 'SetupGet'. Other code stayed the same as sighohwell's code.

What didn't work was the test itself because it cancelled accessing con.HttpContext property because it doesnt exist :|.

Any other clue? Thanks in advance

Eugenio Miró
I referenced System.Web.Mvc,System.Web.Abstractions, System.Web.Routing and Moq (v2.6) in my test project. If you're testing your controllers you should make sure that your test project has exactly the same references as your web application project (sometimes they can go out of sync).
sighohwell