Coding Together: Developing Apps for iPhone and iPad
Wow this is a really great course! Thank you Paul Hegarty you are a great teacher.
Test Driven Development
For myself and many professional developers TDD is something we practice daily. I am a practioner and an advocate. Your code will be better. You will be better. When you working on your old code, you’ll appreciate it. When others are working on your code, they’ll appreciate it.
I don’t have much to say here, I’ve never used it before doing this course. I can advise that you get AppCode. JetBrains IDE’s are awesome and make TDD natural.
Red, Green, Refactor
Say what? Its the TDD workflow:
- Add a test
- Run the tests and see the new test fail
- Write the code to make the test pass
- Run the tests and see they all succeed
To get this working on you with your own project install the latest Xcode and AppCode followed by OCMock. Create a new Empty Application for iOS and follow the OCMock instructions or just clone my repository and open it in Xcode or AppCode, OSMock is already setup.
A little tip for AppCode, if you get an error saying Code Sign error: The identity ‘iPhone Developer’ doesn’t match any valid, non-expired certificate/private key pair in your keychains while running the app or tests choose the Run option from the Run menu and make sure you have the iPhone or iPad emulator selected.
First thing we need to do is write our failing test.
If you run this test your build should fail because we don’t even have a Card class. Compilation failures count as red. Now we’ll write the code to make the test pass. Hint if you’re using AppCode and you’re not familiar with JetBrains IDE’s hit ALT + Enter over the red Card it will prompt you to create the class, do the same with the match method!
If you’ve never practiced TDD before you’re might be saying something like: You’re just returning zero, thats ignorant, the match method does more than that… What I’ve done is the simplest way to pass the test. The tests are the documentation of our code, right now we’ve documented that match should return 0, so that is all our code should be doing. I agree that we probably want our match method to be more useful… so its time to write another test.
Pseudo randomness in tests can be useful, remember to seed your random number and give the seed as part of the feedback, that way if the test ever fails you can repeat the randomness. The randomness means we need to think a little be more about how we make the above test pass. We could not perform a naive lookup on the array index based on the ordering in the test. Randomness excercises our code better. Time to make it Green.
Okay great now the match method is useful. After many more Test classes and Model class I realize I need to override isEqual on Card below are the tests interspersed with the evolving implementation.
Okay now we have isEqual there is a good oppurtunity for a bit of refactoring. Our previous match method had a for loop and an if statement it would be nice to get rid of those.
The benefit of testing really shines now, we can have confidence that our objects are working as we documented (with our tests) even thought we have made a fairly large change to our code (the match method is now 87% smaller).
Being able to mock out dependencies is an important for TDD. It allows us to test the behaviour of our objects, when we either don’t want to or are unable to, expose the results of our interaction with dependencies. As an example lets look at the tests for the addCard method of the Deck class.
Here we’re validating that we are infact adding the card to the backing NSMutableArray *cards. When it comes to mocking I believe you have to be pragmatic, its really powerful but can also couple your tests to your implementations. You can read all about mocks in this post by Martin Fowler.
You have no comments…
Tests are better documentation than any comment, unlike tests, comments never get updated or even validated.
Well if you’ve implemented the homework yourself why don’t you compare you implementation with mine and ask yourself?
- Which is easier to understand.
- Which would you feel more comfortable refactoring.
For a far more detailed explanation by Kent Beck read Test Driven Development: By Example. I also recommend that you read Refactoring: Improving the Design of Existing Code by Martin Fowler.
I strongly recommend you participate in a Code Retreat whether you’re a TDD novice or expert. Pairing with other practioners is the best way you can learn and improve!
We’ll spend time looking at how we can write functional tests for our UI of our application.