Bragi Ragnarson
Bragi Ragnarson

Reputation: 523

BDD in Objective-C

I have recently started to learn Objective-C and write my tests using OCUnit that comes bundled with Xcode.

I'm a long time Ruby programmer and I'm used to RSpec and Cucumber - nice BDD frameworks.

Is there a decent BDD framework to use in Objective-C? I'm missing my 'should's :)

Upvotes: 28

Views: 6004

Answers (6)

djromero
djromero

Reputation: 19641

I'm using Kiwi Library Quick to integrate, works pretty well.

From their github:

describe(@"Team", ^{
    context(@"when newly created", ^{
        it(@"should have a name", ^{
            id team = [Team team];
            [[team.name should] equal:@"Black Hawks"];
        });

        it(@"should have 11 players", ^{
            id team = [Team team];
            [[[team should] have:11] players];
        });
    });
});

Upvotes: 21

user1829404
user1829404

Reputation: 41

You can take a look at BDD From the idea to the app where you'll see an example using calabash.

Upvotes: 3

Don McCaughey
Don McCaughey

Reputation: 9982

Adam Milligan of Pivotal Labs has created a BDD framework for Objective-C called Cedar that targets both Cocoa and Cocoa Touch. It uses blocks in a similar way to RSpec. Here's an example specification:

SPEC_BEGIN(FooSpecs)

sharedExamplesFor(@"a similarly-behaving thing", ^(NSDictionary *context) {
    it(@"should do something common", ^{
        ...
    });
});

NSDictionary *context = [NSDictionary dictionary];

describe(@"Something that shares behavior", ^{
    itShouldBehaveLike(@"a similarly-behaving thing", context);
});

describe(@"Something else that shares behavior", ^{
    itShouldBehaveLike(@"a similarly-behaving thing", context);
});

SPEC_END

Upvotes: 14

Nathan de Vries
Nathan de Vries

Reputation: 15501

There's a relatively new project called uispec which was inspired by RSpec's testing DSL. The example spec looks like this:

#import "DescribeEmployeeAdmin.h"
#import "SpecHelper.h"

@implementation DescribeEmployeeAdmin

-(void)before {
  //login as default admin before each example
  [SpecHelper loginAsAdmin];
}

-(void)after {
  //logout after each example
  [SpecHelper logout];
}

-(void)itShouldHaveDefaultUsers {
  //Check that all default users are in list
  [[app.tableView.label text:@"Larry Stooge"] should].exist;
  [[app.tableView.label text:@"Curly Stooge"] should].exist;
  [[app.tableView.label text:@"Moe Stooge"] should].exist;
}

-(void)itShouldAddAUser {
  //Click the + button
  [app.navigationButton touch];

  //Set the form fields.
  //Also ".with" is optional so we here we can show the different syntax
  [[app.textField.with placeholder:@"First Name"] setText:@"Brian"];
  [[app.textField.with placeholder:@"Last Name"] setText:@"Knorr"];
  [[app.textField.with placeholder:@"Email"] setText:@"[email protected]"];
  [[app.textField placeholder:@"Username"] setText:@"bkuser"];
  [[app.textField placeholder:@"Password"] setText:@"test"];
  [[app.textField placeholder:@"Confirm"] setText:@"test"];

  //Click the Save button
  [[app.navigationButton.label text:@"Save"] touch];

  //Make sure the error alert view doesn't appear
  [app timeout:1].alertView.should.not.exist;

  //User list should now have a new entry
  [[app.tableView.label text:@"Brian Knorr"] should].exist;
}

@end

Keep in mind that I've never used it, so there's a chance it won't fit your needs exactly. But at the very least, you'll be able to use the codebase as inspiration for writing your own test framework.

Upvotes: 17

Chris Hanson
Chris Hanson

Reputation: 55164

Take a look at how the STAssert macros in OCUnit (SenTestingKit, included with Xcode) are implemented.

In your own unit test bundle, you could implement a category on NSObject to add methods like a hypothetical -shouldBeValid which would then call the same pass/fail machinery that the STAssert macros do now.

In case you're not intimately familiar with the C preprocessor...

You'll probably also have to use a #define for your macros to pass through the right values for __FILE__ and __LINE__ when your BDD tests fail. For example, you might have to do something like this:

@interface NSObject (BehaviorDrivenDevelopment)
- (void)shouldBeValidInFile:(const char *)file line:(int)line;
@end

#define shouldBeValid  shouldBeValidInFile:__FILE__ line:__LINE__

That way you would invoke it like this:

[[someObject methodUnderTest:argument] shouldBeValid];

The code the compiler sees will be this:

[[someObject methodUnderTest:argument] shouldBeValidInFile:__FILE__ line:__LINE__];

The __FILE__ and __LINE__ preprocessor macros will expand to the current file and line in your test source file.

This way, when you do have a failing test, it can pass appropriate information to SenTestingKit to send back to Xcode. The failure will show up correctly in the Build Results window, and clicking it will take you to the exact location of the failure in your tests.

Upvotes: 8

Michaël Larouche
Michaël Larouche

Reputation: 847

There is nothing stopping you prefixing your test method with Should. I did that with NUnit in C#.

Upvotes: 0

Related Questions