Unit testing MVC’s Authorize attribute with Rhino Mocks

If there is one thing I often forget to do at initial development time, it is to include an Authorize attribute on my controllers to allow only certain specified roles have access. So I’ve added a check to my ‘template’ of controller tests now.

If you have a controller declaration similar to this:

[Authorize(Roles = "Admin")]
public class MyController : Controller
{
    ...
}

Then you can test for the presence of the Authorize attribute in your test class like so (include a reference to System.Web.Mvc):

[Test]
public void Check_Auth_Privileges_Are_Correct()
{

     AuthorizeAttribute attribute = typeof(MyController)
            .GetCustomAttributes(typeof(AuthorizeAttribute), true)
            .Cast<AuthorizeAttribute>()
            .FirstOrDefault();

     Assert.NotNull(attribute); // Check the attribute exists
     Assert.That(attribute.Roles.Contains("Admin"));  // Check it contains your role
     // Check that it doesn't contain any other roles (if necessary)
}

If you have just declared the attribute on a particular method rather than the whole controller then you can test for its presence by just adding an extra line:

[Test]
public void Check_Auth_Privileges_Are_Correct()
{
     var methodInfo = typeof(MyController).GetMethod("MyMethod");
     AuthorizeAttribute attribute = methodInfo
            .GetCustomAttributes(typeof(AuthorizeAttribute), true)
            .Cast<AuthorizeAttribute>()
            .FirstOrDefault();

     Assert.NotNull(attribute); // Check the attribute exists
     Assert.That(attribute.Roles.Contains("Admin"));  // Check it contains your role
     // Check that it doesn't contain any other roles (if necessary)
}

You can obviously use this method for other annotations too.

Mocking HttpPostedFileBase InputStream with Rhino Mocks

I wanted to unit test a CSV file upload on a new website. I was using a standard file upload HTML input tag, which in .NET MVC translates into an HttpPostFileBase object. The main problem from the point of view of unit testing is that the InputStream method cannot be set directly, so I had to mock it (I use Rhino Mocks).

Here is my example method which can plugged into the test class. It converts a string into a stream and sets the view model’s UploadedFile property to that value. Just pass in the CSV string you wish to test. Note that you may need to change your Encoding method. Hopefully it will be useful in the future.

// The view model
public class MyViewModel
{
        [Required(ErrorMessage = "Please enter a file name")]
        public HttpPostedFileBase UploadedFile { get; set; }
}
// Creating the view model instance with the mocked input stream
private MyViewModel CreateInputModel(string input)
{
    MyViewModel passedModel = new MyViewModel();
    HttpPostedFileBase file = MockRepository.GenerateMock<HttpPostedFileBase>();
    string str = input ;
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
    MemoryStream stream = new MemoryStream(buffer);

    file.Stub(x => x.InputStream).Return(stream);
    passedModel.UploadedFile = file;
    return passedModel;
}

Mocking out and ref parameters with Rhino Mocks

There doesn’t seem to be that much information about how to mock ref and out parametered methods using Rhino Mocks, and what I did find was not overly useful and/or mutually contradictory (maybe I was using the wrong search terms – who knows?). So here is how you do it – and yes it does work with ref parameters too, something that other sites seem to deny.

For testing a method MyMethod in MyClass with the definition:

public void MyMethod(string test, string test2, ref MyObject obj);

Do the following in your test class:


private IMyClass _MyClassMocked = MockRepository.GenerateMock<IMyClass>(); 
 
[Test]
public void Test_Method()
{
        MyObject obj = new MyObject();
        _MyClassMocked.Stub(x => x.MyMethod("test", "", ref obj)).OutRef(
                 new MyObject()
                 {
                    ...
                 }
            );
}

Just change the ref to out for out parameters.