Sunday, September 28, 2014

Programmer's Diary: Constructing your Tests Line by Line

It is a different thought process for everyone, but when I write the tests that will represent the functionality I am about to implement, I always start with the Exercise or Act part.

A unit test is usually composed of three or four parts, thus the rule of 4As

1. Setup or Arrange
2. Exercise or Act
3. Verify or Assert
4. Tear down or Annihilate (this may be missing, automatic garbage collection, anyone?)

I observed that people who know about these parts have the natural tendency to start writing a test in that exact order. They start by asking themselves "What do I need?" and only then "What do I do?". This frequently leads to dilemmas that can not  be answered, and they just give up writing the test and start writing the production code.

In my opinion this type of thinking has a fundamental flaw. You cannot know what do you need before you first figure out what do you want to do. That is why I always start with 2. Exercise or Act. And my second step is always 3. Verify or Assert. This way I can put down the basis of the test by clearly defining what I want to do and what results I am expecting.

I build the 1. Setup or Arrange part as an iterative process by adding all the required dependencies for the already defined lines. Finally I do 4. Tear down or Annihilate to do the opposite of setup if needed.

1. Write a new test function and name it by the behavior you want to test.

function testItCanAddTwoNumbers() {

}

2. Act! Do the behavior you just defined in the test's name.

function testItCanAddTwoNumbers() {
    $sum = $calculator->add($n1, $n2);
}

3. Assert.

function testItCanAddTwoNumbers() {
    $actualSum = $calculator->add($n1, $n2);
    $this->assertEquals($expectedSum, $actualSum);
}

4. Arrange, or prepare all the missing parts.

function testItCanAddTwoNumbers() {
    $calculator = new Calculator();
    $n1 = 1;
    $n2 = 2;
    $expectedSum = 3;

    $actualSum = $calculator->add($n1, $n2);
    $this->assertEquals($expectedSum, $actualSum);
}

5. Annihilate, or destroy persistent information. Nothing to be done for this part here.

That's it. Have fun writing tests instead of hitting a brick wall with your head!