An introduction to unit testing: How do unit tests work?

by Leon Cullens 22. februari 2012 18:34

Now that you know what test-first means and how you can build a testable architecture, you are ready to start writing some real unit tests. This chapter will explain what kind of assertions you have, how a good unit test is set up and more.

Mocks vs. Stubs

Before I start explaining how to build a unit test, I will first briefly describe what mocks and stubs are. Mock objects and stub objects are both 'fake' objects. This means that we can just 'mock' an object (our repository for example), creating a fake implementation of that object, that does nothing. This is useful because we now no longer have to query against the database, we just query against our fake object that says "al right, I received some data from the database, here you have it".

The difference between mocks and stubs is that mock objects can let your tests fail. A mock repository allows us to validate that our repository's 'Add' method was called, raising an exception if it wasn't called. Or we could validate that our methods were called in a specific order. Stub objects on the other hand are just empty objects that don't track your actions.

Some people will make this distinction, some people treat both mock objects and stub objects as 'fake' objects, not caring about their behaviour, which is OK in my opinion.

Frameworks

To start with, you'll need a unit testing framework that contain the assertions you will need, and are often able to run your tests. Below is a small list of frameworks:

  • .NET - NUnit
  • .NET - MSTest (built in with Visual Studio)
  • Java - JUnit
  • PHP - PHPUnit
  • Python - PyUnit

Again, you can find a more extensive list here.

The structure

When writing unit tests, you usually have at least one test class for each class you want to test, and at least one test method for each method that you want to test. You should put these test classes in a different project, usually named [Projectname].Tests. When you are writing a test class you should let the frameworks know that it is a test class. How you do this depends on the framework. Some frameworks rely on convention such as PHPUnit, other frameworks require you to mark the class with an annotation. MSTest for example requires a [TestClass] attribute above the class and a [TestMethod] attribute above each test method, where PHPUnit 'requires' you to start the name of your test method with 'test' to indicate that it is a test method (PHPUnit has annotations as well, but it's easier to stick to the conventions).

Not only can you create test methods inside your test class, you can also create methods that are run before each individual test and methods that are run when an object of that class is created. There are also similar 'teardown' methods; one that is run after each individual test and one that is run just before the object is destroyed. These kind of methods are useful to set up some test data that is used across all methods, or to clean up resources after using them, resulting in better performance.

Below is a small example of this:

[TestClass]
public class CalculatorTests
{
    private Calculator _calculator;

    [TestInitialize]
    public void Initialize()
    {
        _calculator = new Calculator();
    }

    [TestMethod]
    public void Sum_Add1And2_ShouldReturn3()
    {
        // Arrange
        const int expected = 3;

        // Act
        var result = _calculator.Sum(1, 2);

        // Assert
        Assert.AreEqual(expected, result);
    }
}

There are a couple of interesting things about the example above; first we see the initialize method and a test method as discussed above. The second thing we notice is the strange name for the test method. It consists of: [MethodName]_[ActionToPerform]_[ExpectedResult]. So we're testing the Sum method and we expect it to return 3 if we input 1 + 2. We do this because it allows us to see directly what is wrong when our test fails. Having a name that describes the scenario does indeed result in very long names, but it gives you a lot of information, especially if you want to print reports about your unit test runs.

The third thing we can see is the AAA, or Arrange - Act - Assert pattern. It means that each test method has 3 parts: the part where you arrange the data and objects you need (arrange), the part where you perform the action (act) and the part where you validate the output (assert). This is a very useful pattern because it gives you a nice structure for your tests.

Assertions

The pieces of code that validate the result of your tests are usually the Assertions (or sometimes the Verify method of your mock objects). There are different kind of assertions. The most common kind of assertions (I will just describe them, the syntax varies slightly between different frameworks and languages) are:

  • Assertions that verify that two variables (don't) have the same value
  • Assertions that verify that two objects (don't) have the same reference
  • Assertions that verify that a variable is (not) null
  • Assertions that verify that a variable is true/false
  • Assertions that verify that an object is (not) of a specific type

Some frameworks provide different kind of assertions, but must of them have the assertions that are listed above.

Next: Step-by-step walkthrough

Tags: , , , , , , ,

Testing

Pingbacks and trackbacks (2)+

Comments are closed

about

Name: Leon Cullens
Country: The Netherlands
Job: Software Engineer / Entrepreneur
Studied: Computer Science 
Main skills: Microsoft technology (Azure, ASP.NET MVC, Windows 8, C#, SQL Server, Entity Framework), software architecture (enterprise architecture, design patterns), Marketing, growth hacking, entrepreneurship

advertisements

my apps