Showing posts with label xUnit. Show all posts
Showing posts with label xUnit. Show all posts

Tuesday, 24 July 2012

How to Use Assert.IsAssignableFrom in xUnit

Assert.IsAssignableFrom<{type}>({object}) method means whether {type} is assignable from the type of {object} which also means whether {object} has a type similar to or is derived from {type}. While Assert.IsType method is used to test an object against a particular type, Assert.IsAssignableFrom offers more flexibility.

Let us look at some examples of this. Say that we have these classes:
public class BaseClass{}
public class TestClass : BaseClass{}
public class DerivedClass : TestClass{}

Then when we write these unit tests below. The results are commented out on each test.
public class Test
{
    private TestClass testClass;

    public Test()
    {
        testClass = new TestClass();
    }

    [Fact]
    public void test1() //Pass
    {
        Assert.IsType<TestClass>(testClass);
    }

    [Fact]
    public void test2() //Pass
    {
        Assert.IsAssignableFrom<TestClass>(testClass);
    }

    [Fact]
    public void test3() //Pass
    {
        var result = Assert.IsAssignableFrom<BaseClass>(testClass);
        //Assert.IsType<BaseClass>(result); //failed
        Assert.IsType<TestClass>(result);
    }

    [Fact]
    public void test4() //Pass
    {
        var result = Assert.IsAssignableFrom<Object>(testClass);
        //Assert.IsType<Object>(result); //failed
        //Assert.IsType<BaseClass>(result); //failed
        Assert.IsType<TestClass>(result);
    }

    [Fact]
    public void test5() //Failed
    {
        Assert.IsAssignableFrom<DerivedClass>(testClass);
    }
}
Note that when using implicit type 'var' to hold the result of Assert.IsAssignableFrom method, the new variable's type is still the same as the tested object type (line 26 & 34).

Saturday, 30 June 2012

xUnit Examples of Testing Controller Actions

We will see some examples of unit tests using xUnit testing framework to test controller actions. Let say we have these controller actions:
public ViewResult Add()
{            
    return View("Add", new StuffViewModel());
}


[HttpPost]
public ActionResult Add(StuffViewModel stuffViewModel)
{
    if (ModelState.IsValid)
    {
        Stuff stuff = mappingService.Map<StuffViewModel, Stuff>(stuffViewModel);
        stuffRepository.InsertOrUpdate(stuff);
        return RedirectToAction("List");
    }
    return View("Add", stuffViewModel);
}
As you can see both actions use same view. The first action is for displaying the view (HTTP GET) and the other is for handling submission from the view (HTTP POST).

Then below are the unit tests to cover both actions functionalities:
public class Add
{
    private Mock<IStuffRepository> stuffRepository;
    private Mock<IMappingService> mappingService;
    private StuffsController controller;

    public Add()
    {
        stuffRepository = new Mock<IStuffRepository>();
        mappingService = new Mock<IMappingService>();
        controller = new StuffsController(stuffRepository.Object, mappingService.Object);
    }


    [Fact]
    public void GET_should_return_add_view()
    {
        // Arrange

        // Act
        var result = controller.Add();

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Equal("Add", viewResult.ViewName);
    }

    [Fact]
    public void GET_should_have_StuffViewModels()
    {
        // Arrange

        // Act
        var result = controller.Add();

        // Assert
        //Assert.IsAssignableFrom<StuffViewModel>(result.ViewData.Model); 
        Assert.IsType<StuffViewModel>(result.ViewData.Model);
    }

    [Fact]
    public void POST_should_save_to_database_if_model_is_valid()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1};
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
                
        // Act
        controller.Add(stuffViewModel);

        //Assert
        stuffRepository.Verify(o => o.InsertOrUpdate(stuff), Times.Once());
    }

    [Fact]
    public void POST_should_redirect_to_list_view_after_saving()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        var redirectToRouteResult = Assert.IsAssignableFrom<RedirectToRouteResult>(result);
        Assert.Equal("List", redirectToRouteResult.RouteValues["action"]);
    }

    [Fact]
    public void POST_if_not_valid_should_not_save_into_database()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
        controller.ModelState.AddModelError("key", "error");

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        stuffRepository.Verify(o => o.InsertOrUpdate(stuff), Times.Never());
    }

    [Fact]
    public void POST_if_not_valid_should_return_to_add_view()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
        controller.ModelState.AddModelError("key", "error");

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Equal("Add", viewResult.ViewName);
    }

    [Fact]
    public void POST_if_not_valid_should_return_view_with_StuffViewModel()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
        controller.ModelState.AddModelError("key", "error");

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.IsType<StuffViewModel>(viewResult.ViewData.Model);
    }
}