views:

99

answers:

1

I am currently writing some unit tests for an ASP.NET MVC 2 controller and having some issues with the MVC 2.0 validation attributes. The validation attribute in question uses a repository to check that no duplicate names exist in the current data source, and I would like to replace this repository with a fake one during my unit test. I am using Castle Windsor, as per this article, which allows me to replace the repository at run time, but am not sure how I can do this during the unit test.

The bulk of the test code is this:

[TestMethod]
    public void TestSaveDuplicateTitleNameReturnsValidationErrorView()
    {
        //Arrange
        var titleRepository = new FakeTitleRepository();
        var controller = new TitleController(titleRepository);            

        var selectedTitle = new Title();
        selectedTitle.Name = "Fru";

        //Act
        var actual = controller.Save(selectedTitle);

A code sample from the controller is below:

 public ActionResult Save(Title SelectedTitle)
    {
        if (TryValidateModel(SelectedTitle))
        {
            TitleRepository.Add(SelectedTitle);
            TitleRepository.Save();

The repository being used in the controller itself during the test is my fake one that I have passed, but when the TryValidateModel fires and the following code is run then it causes an exception as the repository is null:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class ValidTitleNameAttribute : ValidationAttribute
{
    public ITitleRepository Repository { get; set; }

    public override bool IsValid(object value)
    {
        bool isValid = true;

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
        object name = properties.Find("Name", true).GetValue(value);

        if (name == null)
        {
            return isValid = false;
        }

        var titles = Repository.GetAllTitles();

Obviously in the repository property I could set a default instance to reference a concrete repository, which would prevent the exception during testing but that would defeat the purpose of using the IoC container. What would be the best way round this issue, would it be to find a way to mock the validation attribute in some way, or is there a way Windsor can inject the fake repository when the unit test runs? Any help/advice would be much appreciated.

+1  A: 

I think the best thing to do would be to create a fake DataAnnotationsModelValidator for your unit test that will inject your fake repository during testing. You should be able to make it fairly simple so as to limit the chances of it causing any issues with your unit tests.

Patrick Steele