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;
}

‘NUnit has stopped working’ message after crash

My PC crashed recently and after reboot NUnit refused to launch. It crashed when double clicking the icon with the generic Windows error ‘ has stopped working’. The message also tells you that Windows is trying to find a reason but then just exits. I obviously tried rebooting, uninstalling/reinstalling etc.

If this happens, try to launch NUnit from the command window – the default location of the executable is C:\Program Files (x86)\NUnit 2.6.1\bin\nunit-console.exe. The same error message will appear, but now on the command window you should see a stack trace that might help. For me, it told me that NUnit was trying to load a ‘settings’ file but couldn’t. Unfortunately it didn’t say where that file was. In this case, try to use the Debug button on the error message to launch Visual Studio. If this brings up the exception (it doesn’t always seem to – you may have to try a few times) then click on View Detail on the Exception window to find the details of the exception. I found my answer in the InnerException->SourceUri property, and so possibly you will too!

For me, I found that it was trying to load a file called NUnitSettings.xml, from my AppData\Local\NUnit directory. This file must have become corrupted when my PC crashed, as it was empty. NUnit was moaning about this. I simply deleted the file and voila, I was back up and running with NUnit again.

Using web.config application settings in nUnit

If the piece of code that you are testing refers to an appsetting value in the web.config file then nUnit will fall over – basically because nUnit itself does not use the web.config file.

This is a fairly common thing to come up against, and the easy solution is on the web, but it doesn’t appear to be in the nUnit help so I thought I’d put it here too, and make it specific to the dependency injection/Sharp Architecture web projects that my team use.

There are two things that you can do. The quick thing to do is to find your tests dll file. In a Sharp Architecture 1.6 project this will be in something like [project root]/tests/[namespace].Tests/bin/Debug. The dll file will be called (unsurprisingly) [namespace].Tests.dll.

You will see that nUnit has also created a [namespace].Tests.dll.config file. This is where you should put your application settings. When you open it up you can see that it looks similar to the web.config file – there is already an appsettings section. Simply copy your web.config settings to here.

That is all very well, but what if you want to mock different values of this app setting when you are testing? If you are using a dependency injection development pattern you might also want to consider having a separate class and interface that just handles the retrieval of application settings, e.g.

public class AppSettingsService: IAppSettingsService
{
        public string ManagerRole
        {
            get { 
              if (ConfigurationManager.ConnectionStrings["ManagerRole"] == null)
                 return "";
              else
                 return ConfigurationManager.ConnectionStrings["ManagerRole"].ToString();  
            } 
        }
}

You can then inject this service class into the class that you are testing, use the methods on this service class to retrieve your appsettings, and mock them to your heart’s content.

Note: I am assuming you know what dependency injection, mocking, interfaces etc are. If not I suggest searching the net – they are a very good way of developing!

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.

Unit testing MVC Controllers with Model Validation

If you use ModelState.isValid in your controller classes then you will run into problems during unit testing as it will always return true as Model Validation occurs during the Request pipeline, which isn’t the route followed during testing

To overcome I’ve implemented a static controller extension “CallWithModelValidation” as seen below:

public static class ControllerExtensions
    {
        //Enforeces model validation during testing. This is required because model binding doesn't occur in 
        //during testing which means that ModelState.IsValid is always true
        //Taken from
        //http://blog.overridethis.com/blog/post/2010/07/08/MVC2-Validation-and-Testing-e28093-Refactored.aspx
        public static ActionResult CallWithModelValidation<C, R, T>(this C controller
            , Func<C, R> action
            , T model)
            where C : Controller
            where R : ActionResult
            where T : class{
            DataAnnotationsModelValidatorProvider provider = new DataAnnotationsModelValidatorProvider();

            IEnumerable<ModelMetadata> metadata = ModelMetadataProviders
                .Current
                .GetMetadataForProperties(model, typeof(T));
            foreach (ModelMetadata modelMetadata in metadata) 
            {
                IEnumerable<ModelValidator> validators = provider
                    .GetValidators(modelMetadata, new ControllerContext());
                
                foreach (ModelValidator validator in validators) 
                {
                    IEnumerable<ModelValidationResult> results = validator.Validate(model);
                    foreach (ModelValidationResult result in results)
                        controller.ModelState.AddModelError(modelMetadata.PropertyName, result.Message);
                }
            }
            return action(controller);
        }
    }

This can then be called in your controller test by doing the following (where in the case below “AddSupplier” is the controller method under test):

_testController.CallWithModelValidation(m => m.AddSupplier(viewModel), viewModel).AssertViewRendered().ForView("CreateSupplier");