Saturday, August 24, 2013

How to create a unit test that expect an exception?

In creating unit tests, we want to get maximum code coverage to make sure we are testing all possible scenarios and outcomes of our code. When we have a possible path of execution that leads into an exception being thrown, how do we build a test for that?

Consider this simple method "GoToPage" that takes in an integer as a parameter in the "Book" class.
public class Book
{
    // ...

    public void GoToPage(int page) 
    {
        if (page < 1)
            throw new ArgumentException("Page must be a positive, non-zero integer", "page"); 
        if (page > TotalPage)
            throw new ArgumentException("Page cannot be more than the total page count", "page"); 

        // ...
    }

    // ...
}
So how do we test those boundary scenarios? We can do something like this:
[TestMethod]
public void NegativePage_Exception()
{
    // arrange
    var book = new Book();

    // act
    try 
    {
        // act
        book.GoToPage(-1);
    }
    catch (ArgumentException e)
    {
        // assert
        Assert.AreEqual("Page must be a positive, non-zero integer", e.Message);
    }
    catch (Exception) {
        Assert.Fail();
    }
}
Or, you can write a more concise test such as this:
[TestMethod]
[ExpectedException(typeof(ArgumentException), "Page must be a positive, non-zero integer")]
public void NegativePage_Exception()
{
    // arrange
    var book = new Book();

    // act
    book.GoToPage(-1);
}
-- read more and comment ...

Thursday, August 22, 2013

Creating data validation unit test

Creating a unit test is pretty simple for a method, but when your business/POCO objects are relying on DataAnnotation for validation, how do you make sure that they are implemented and tested? Obviously, one can create all the classes run the test from the UI and check whether one can enter invalid data. Is there another way of doing this instead of waiting to test them from the UI? If we are doing TDD, can we build the test first?

For example, let's say we have this class "Person", which requires that both first name and last name to be required, but middle name is optional.
public class Person
{
    [Required]
    public string FirstName { get; set; } 

    public string MiddleName { get; set; } 

    [Required]
    public string LastName { get; set; } 
}
There are several ways to create tests for this class - the first one is to check whether the property is decorated with the RequiredAttribute.
[TestMethod]
public void Person_FirstName_IsRequired()
{
    // arrange
    var propertyInfo = typeof(Person).GetProperty("FirstName");
 
    // act
    var attribute = propertyInfo.GetCustomAttributes(typeof(RequiredAttribute)).Cast().FirstOrDefault();
 
    // assert
    Assert.IsNotNull(attribute);
}
Or another way is by testing the validation itself.
[TestMethod]
public void Person_FirstName_IsRequired()
{
    // arrange
    var person = new Person();
    var context = new ValidationContext(person, null, null);
    var validationResults = new List();

    // act
    var isValid = Validator.TryValidateObject(person, context, validationResults);

    // assert
    Assert.IsTrue(validationResults.Any(e => e.ErrorMessage == "The FirstName field is required"));
}
-- read more and comment ...