Last Updated: February 25, 2016
·
811
· adamyanalunas

Group success and failure test cases

Tests can be documentation. To that end, help fellow developers to quickly understand how your code is supposed to not only work but how it's expected to fail as well.

Imagine you have a snippet like this. It's Objective-C but the logic should be easy enough to transfer elsewhere.

- (void)storeMagicNumber:(int)num
{
    if (num == 42)
    {
        [self storeNumber:num];
    }
    else
    {
        @throw [NSException exceptionWithName:@"MagicNumber" reason:[NSString stringWithFormat:@"%i is not a magic number.", num] userInfo:nil];
    }
}

The above code accepts any integer but will throw an error if it's not 42. If you do supply the magic number it shuffles it off to some helper method to store it.

Your tests should look something like below. I'm using Kiwi syntax but, again, the logic should be transferrable to other tests.

describe(@"storeMagicNumber:", ^{
    context(@"Success, ^{
        it(@"should ask to store the supplied number if it's the magic number", ^{
            ...
        });
    });

    context(@"Failure", ^{
        it(@"should throw an error if magic number not supplied", ^{
            ...
        });

        it(@"should have the supplied number in the exception message", ^{
            ...
        });
    });
});

Just a bit of simple grouping allows for faster scanning and grouping of setup and teardowns for specific cases. That latter detail becomes super duper helpful as you start making heavier use of stubbing, especially around things like network requests, database lookups and async calls.

Go forth, organize accordingly and make your fellow devs happy!