allending/Kiwi — pull request #416 by RCacheaux (2013-11-30 07:17:50+00:00)
Title: Adding story, given, when, and then functions to allow for acceptance tests in Kiwi

Hi guys,

Our team has been using Kiwi to write acceptance style given-when-then tests. We found that mapping given-when-then to describe-context-it was confusing to new folks, so we wrote the following tiny wrapper functions to make our acceptance test specs easier to read. Since this is a popular testing dialect, we thought others might want to use these functions as well. If you guys like this addition, I'd be more than happy to add some docs and examples on the wiki.

### Examples
```objc
SPEC_BEGIN(CreateGameSpecification)

story(@"As an athlete I want to create a new game so that I can find other athletes to play with", ^{
given(@"a valid start time, valid location and no group", ^{
NSString *groupID = nil;
NSDate *startTime = [NSDate date];
NSString *location = @"Delta Park";

__block Game *gameToAssert;
__block NSError *errorToAssert;
beforeEach(^{
gameToAssert = nil;
errorToAssert = nil;
});
when(@"an athlete attempts to create a game", ^{
NSObject *database = [KWMock mockForProtocol:@protocol(GameDatabase)];
createGameForGroupWithOnComplete(groupID, startTime, location, database, ^(Game *game, NSError *error) {
gameToAssert = game;
errorToAssert = error;
});
}, ^(KWWhenActionBlock act){
then(@"the game should not be created", ^{
act();
[[expectFutureValue(gameToAssert) shouldNotEventually] beNonNil];
});
then(@"there should be an error", ^{
act();
[[expectFutureValue(errorToAssert) shouldEventually] beNonNil];
[[errorToAssert.domain should] equal:MMErrorDomain];
[[theValue(errorToAssert.code) should]
equal:theValue(MMErrorCodeGameCreateInvalidGroupIDArgument)];
});
});
});

given(@"a valid group, start time, and location", ^{
NSString *groupID = @"1";
NSDate *startTime = [NSDate date];
NSString *location = @"Delta Park";

__block NSObject *database;
__block Game *gameToAssert;
__block NSError *errorToAssert;
beforeEach(^{
database = [KWMock mockForProtocol:@protocol(GameDatabase)];
[database stub:@selector(saveGame:)];
gameToAssert = nil;
errorToAssert = nil;
});
when(@"an athlete attempts to create a game", ^{
createGameForGroupWithOnComplete(groupID, startTime, location, database, ^(Game *game, NSError *error) {
gameToAssert = game;
errorToAssert = error;
});
}, ^(KWWhenActionBlock act) {
then(@"a new game should be created", ^{
act();
[[expectFutureValue(gameToAssert) shouldEventually] beNonNil];
});
then(@"a new game should be saved in the database", ^{
// Allows for reusable action blocks with interaction/message expectations.
[[database should] receive:@selector(saveGame:)];
act();
[[expectFutureValue(gameToAssert) shouldEventually] beNonNil];
});
});
});
});

SPEC_END
```

### New Functions

#### story
Purely a wrapper around ```describe```.

#### given
Wrapper around ```context``` that prepends the description string with 'given '.

#### when
This is the only function that is not a straight up wrapper. It takes in two blocks. The first one defines the 'when' action and the second one is equivalent to the block passed in to ```context```. The first block is similar to ```beforeEach``` except that the block has to be manually executed within each ```it```/```then``` block. In each ```then``` block, this allows you to setup any interaction and message expectations before running the code under test. This also allows you to associate a description string to the logic your are exercising.

#### then
Wrapper around ```it``` which prepends the description string with 'then '.