Need-Driven Development

I recently came across a 10 year old article titled “Mock Roles, not Objects“. I recall reading this article at some time in the past, but I guess that I really didn’t get it the first time. This article is awesome, and I recommend reading it. But maybe like me, you need to become fairly familiar with TDD and using mock objects before it will have much impact on your thinking.

When I reread the article, I was immediately struck by the opening 2 sentences:

“Mock Objects is an extension to Test-Driven Development that supports good Object-Oriented design by guiding the discovery of a coherent system of types within a code base. It turns out to be less interesting as a technique for isolating tests from third-party libraries than is widely thought.”

Wow. The article then goes on to explain how the proper use of Need-Driven Development can help in the creation of good, clean architecture. I think that maybe the first time I read this article, I was still stuck in creating relatively few, large objects with lots of methods. After repeated viewings of Uncle Bob’s videos though, I changed my mindset to using lots of small, SRP compliant objects. Without that mindset, it might be possible to misinterpret this article as recommending the use of partial mocks to intercept calls from one method to another within the same object. Been there, done that, got help and am hopefully on the road to recovery now.

I think that there are still parts of this article that I’m not evolved enough yet to fully grok, for example section 4.1. I think I’ll come back and reread the article in another year or so and see if I get it then.

How is everybody liking XCTest?

Ok, Xcode 5 and XCTest have been out for awhile now. What has been your experience with it?

I’ve used it for some simple projects, doing TDD with it. I’ll have more to say about that in the near future. But I have to say that I really like the tighter integration of unit testing into Xcode.

One of my favorite things is the speed at which I can perform the TDD loop. This has been boosted by a couple things: the test classes assistant, and the ability now to rerun a single test by clicking on the symbol next to the line number (red “x” for a failing test, green checkmark for a passing test).

In the screen capture below, I’m using the test classes assistant to display the associated unit test case file on the right. I’ve just run tests, and the test at line 37 on the right failed, and is highlighted. Note that the other tests have a green checkmark next to them.

Although you can’t tell from this screen capture, I’m hovering the mouse over the red checkmark left of the line number at line 37, which has caused the checkmark to switch to a right arrow. Clicking on this reruns just that test. How cool is that!

Xcode test assistant

XCTest example of failing test

XCTest Assertions

XCTest supports the following assertions. This list is essentially the same as the list of assertions supported by SenTestingKit, but with the “ST” prefix changed to “XCT”.

  • XCTFail (format…)
  • XCTAssertNil (a1, format…)
  • XCTAssertNotNil (a1, format…)
  • XCTAssert (a1, format…)
  • XCTAssertTrue (a1, format…)
  • XCTAssertFalse (a1, format…)
  • XCTAssertEqualObjects (a1, a2, format…)
  • XCTAssertEquals (a1, a2, format…)
  • XCTAssertEqualsWithAccuracy (a1, a2, accuracy, format…)
  • XCTAssertThrows (expression, format…)
  • XCTAssertThrowsSpecific (expression, specificException, format…)
  • XCTAssertThrowsSpecificNamed (expression, specificException, exceptionName, format…)
  • XCTAssertNoThrow (expression, format…)
  • XCTAssertNoThrowSpecific (expression, specificException, format…)
  • XCTAssertNoThrowSpecificNamed (expression, specificExcepton, exceptionName, format…)

Refer to XCTestAssertions.h. The easiest way to locate this file is to Ctrl+Click on an assertion (such as “STFail”), and select “Jump to Definition”.

 

XCTest First Impressions

One of the big improvements in Xcode 5 is unit testing. Woohoo!!!

  • A Test Navigator has been added.
  • The Assistant Editor provides new test categories that place code and tests side by side.

SenTestingKit has been replaced with XCTest. This appears to be essentially just a renaming of SenTestingKit to XCTest, with assertions renamed from ST* to XCT*. For example, STAssertTrue is now XCTAssertTrue.

Also, the previous concept of “Logic” and “Application” tests is gone. By default, all tests are now “application tests”.

The Xcode 5 templates also do not provide an option to “Include unit tests”. Unit tests are always included. And there is an option in Xcode 5 to convert existing OCUnit (SenTesting) projects to use XCTest, making it easy to make the change.

I guess unit testing is finally a first class citizen in iOS development now.

Using Storyboards

We generally do not use Storyboards in our projects where I work. That’s mainly because, at least as of iOS 6, they cannot be merged. This means that only a single developer can make changes to a storyboard at any given time. However, it appears that Apple is working on correcting this situation. So I’ve been taking another look at Storyboards, and investigating how these can be integrated into our best practices (TDD, clean code and architecture).

The first question that I had was “how to unit testing view controllers loaded from a storyboard?”. This appears to be fairly easy, and I found the answer on Rafael Adson’s blog. Simply load the view controller from the storyboard in the test setUp method:

- (void)setUp
{
    [super setUp];
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    self.vc = [storyboard instantiateViewControllerWithIdentifier:@"main"];
    [self.vc performSelectorOnMainThread:@selector(loadView) withObject:nil waitUntilDone:YES];
}

You’ll need to set the identifier for the view controller in the storyboard, and then modify the code above to match the name of your storyboard and the id you chose for the view controller.

The second question is how to integrate storyboards into the VIPER architecture. First off, it seems that the storyboard should replace the wireframe component. But there’s a problem. Normally the wireframe would be responsible for creating the view controller, interactor, and presenter. But the storyboard only creates a view controller.

Now, we can easily have the view controller’s viewDidLoad method create the interactor and presenter, but that results in making the view controller aware of those components. From a clean architecture perspective, we’d prefer that these components remain as detached from each other as possible.

That said, I don’t know how the storyboard can be used to create all three components, so I guess we’re stuck with the viewDidLoad hack at this point. I’m continuing to investigate, and I’d love to hear your suggestions.

Using Kiwi for BDD plus TDD

This past week I helped out one of our large project teams to knock down their bug backlog. This was code that I hadn’t really worked with before. It was delightful to work with a state of the art, new code base that fully utilized great architecture (VIPER), Uncle Bob’s clean code practices, extensive unit test coverage using Kiwi and OCUnit, and automated UI tests using KIF. Understanding the code was easy, and locating the correct spot in the code needing changes was very straight forward, a result of both good architecture and clean coding. I was even more delighted to find that the code needing changes was covered with Kiwi tests. I absolutely love working with Kiwi (debugging difficulties aside). It is so incredibly flexible, just about any type of testing can be accommodated (ATDD, BDD, TDD). I still have a lot of room for improvement in my skills at combining all of these though, and am hoping to take my skills in using it to higher levels.

One of the things that occurred to me (I apologize if I’m late to the party on this one) is that ATDD/BDD style tests can be facilitated by creating helper methods to abstract actions, states, and setting up state such as displaying a particular screen. For example, firstScreenIsDisplayed, acceptButtonWasTapped, userIsLoggedIn:, and displaySecondScreen. These can all probably be added to a Wireframe object (in VIPER architecture). Doing this would allow BDD tests to be clearly written such as:

describe(@"First screen", ^{
   __block Wireframe *wireframe;
   wireframe = [[Wireframe alloc] initForTesting];      
   [wireframe firstScreenIsDisplayed];
   context(@"user is NOT logged in", ^{
      [wireframe userIsLoggedIn:NO];
      context(@"Accept button is tapped", ^{
         it(@"issues a notification to log in", ^{
            [[[wireframe should] receive] displayLoginNotification];
            [wireframe acceptButtonWasTapped];
         });
      });
   });
   context(@"user is logged in", ^{
      [wireframe userIsLoggedIn:YES];
      context(@"Accept button is tapped", ^{
         it(@"goes to second screen", ^{
            [[[wireframe should] receive] displaySecondScreen];
            [wireframe acceptButtonWasTapped];
         });
      });
   });
});

This is just a rough draft of code, and probably syntactically incorrect. I’m going to build some tests using this approach, and will clean up the syntax and provide some more detail as I work it out. For example, readability is better without beforeEach/All (and left out above), so I want to see which happens if code is inserted without one of these (I’m hoping the same as beforeAll).

Converting OCUnit to XCTest

My first attempt at converting a real project to XCTest in Xcode 5 went fairly well. The project was fairly simple, and had 582 OCUnit Application tests using OCHamcrest assertions. I performed this using Xcode 5 DP3, so the issues I encountered should have been fixed by the time you read this.
Xcode 5 supports both OCUnit and XCTest, so the app loaded and the tests ran ok. Interestingly, the Test Navigator displayed all of the OCUnit tests nicely. I had wondered whether or not the Test Navigator only worked with XCTests. It works with both though.
Once all the tests were passing, I then used the “Edit -> Refactor -> Convert to XCTest” menu option to convert the OCUnit test target to XCTest. I wasn’t sure what was going to happen, but had Git ready to undo any changes if/when things got messed up. It turned out that I didn’t need to do this.
The conversion worked almost perfectly. This isn’t a tough operation, basically just changing the #import from SenTestingKit to XCTest, and changing the test case class parent from SenTestCase to XCTestCase.
This conversion reused the same target, without renaming it. So things look pretty much the same in the Test Navigator before and after the conversion.
Then I tried to run the tests. I expected that the tests would fail, or maybe even fail to compile due to OCHamcrest. What happened though was that Xcode 5 crashed. However, upon restarting Xcode 5, I could then select to run the tests without crashing, but got a linker error.
The conversion operation did not add the XCTest framework to the converted target. It did remove the SenTestingKit framework though. So this is probably just a bug in DP3. I submitted radar 14470998 which is fixed in the latest code.
After adding XCTest to the test target’s link build step, all tests ran and passed!
I have wondered, and talked with other developers that I work with, about why Apple would simply rename SenTestingKit to XCTest. It doesn’t appear that much if anything is functionally different. I’ve come to the conclusion (and the hope) that this is just the beginning. Having a totally separate, new framework allows Apple to make changes and additions going forward, without worrying about breaking legacy SenTestingKit users. Let’s hope that this is a new start for unit testing support from Apple.

 

Using “Refactoring” as an Excuse to Skip Writing Tests

I caught myself falling into a bad practice this week. I was starting to use the “Refactor” phase of the TDD loop (Write a test, Write code to pass test, Refactor) to implement new code. In the Who’s Working On What code, at the end of May 27th, commit fb9990…, I had just about everything working with just a single project displayed for each engineer.

So the next thing I wanted to implement was to display more than 1 project for (some) engineers. I’d setup the simple structures to allow 2 to be displayed, knowing that at some point I’d need to make this a variable number using an array of projects.

So I erroneously thought to myself, “let’s just refactor the code to use an array instead of fixed properties. I already have a bazillion tests (about 300), so they should catch any issues.

This might have been an ok approach (but not a great one), except it became hard to tell when I started adding new functionality. Luckily, I had chosen to work off of a branch. When it became apparent that what I was doing was wrong, I simply killed the branch and started over. The problem with that approach is that it allows new code to be written (under the guise of “refactoring”) that might not be actually tested. And one of the chief benefits of TDD is that you can be sure that all the code you write is tested.

So, another lesson learned (or “relearned”?). Only write code that the tests compel you to write.