Title: smb:zambeellearningtdd
1smb//zambeel/learning/tdd
smb//192.168.0.5/learning/tdd
- Demo project for this presentation,
MyTemperatureCalculator.zip also available at the
above link
2iPhone Unit Testing with Google Toolbox for Mac
(GTM)
- Muhammad Ishaq
- Software Engineer, Tintash (Pvt) Ltd
- 01/15/2009
NOTE This presentation is based on the OCUnit
article at http//developer.apple.com/tools/unitt
est.html
3Google Toolbox for Mac (GTM)
- From GTM Homepage
- A collection of source from different Google
projects that may be of use to developers working
other Mac projects. Also includes the Google
Developer Spotlight Importers. - Whats in it for Us?
- Unit testing for the iPhone at least
- may be a lot more (note to self Explore)
4Lets get to business
- Download and extract google-toolbox-for-mac (GTM)
from http//code.google.com/p/google-toolbox-for-
mac/downloads/list - In your Xcode project
- create a new target to run the unit tests, lets
call it RunAllTests - from google-toolbox-for-mac/UnitTesting/, add
these to RunAllTests target - GTMIPhoneUnitTestMain.m
- GTMSenTestCase.h/GTMSenTestCase.m
- GTMIPhoneUnitTestDelegate.h/GTMIPhoneUnitTestDeleg
ate.m - you also need to add google-toolbox-for-mac/GTMDef
ines.h - add a new Run Script Build Phase to the end of
target phases - shell should be set to /bin/sh
- and the script to google-toolbox-for-mac/UnitTest
ing/RunIPhoneUnitTest.sh - thats it, build the target, if you hit Build and
Go, Unit Tests would be executed twice (once for
Build and once for Run)
5GTM Is Configured, Lets Code
- So heres the problem statement
design a class that - can convert from
Centigrade to Kelvin
- We are doing TDD, so lets write a test for the
requirement
6Create a TestCase Class
- Add a new class to the target via File New File
and choose "Objective-C test case class" from the
Mac OS X Cocoa group - Call it TestTempratureCalculator1
- 1 We plan to call our class TemperatureCalculato
r, the test case class by convention should be
called TestTempratureCalculator
7Initial .h file
NOTE the lines I modified are highlighted in
yellow
8Initial .m file
9Lets add our first Test Case
- converting 0C to Kelvin should return 273K, unit
test declaration is highlighted below
NOTE the lines I modified are highlighted in
yellow
10and here is the implementation
NOTE the lines I modified are highlighted in
yellow
11Build the RunAllTests target
- ofcourse, we need to add TemperatureCalculator
with a convertFromCentigrade method defined for
the target to compile
- but since we are writing code essentially to pass
the test, well make convertFromCentigrade to
return hardcoded 273, its enough to pass our
tests (for now).
12Add the missing code
- Adding the missing code makes the test pass
13How about another test?
- okay, our TemperatureCalculature can successfully
convert freezing point to Kelvins (or so it
seems), how about boiling point? - add a new test case called testBoilingPointConvers
ion that should check that converting 100C
should return 373K, it should be declared like
this
14and the implementation is
- now if we try to build the RunAllTests target, it
fails
15update the code
- the failing test complains that
TemperatureCalculator returned 273 instead of 373
(the expected value), turns out return hard-coded
273 was not a good idea after all. Lets update it
our tests pass now, but!
16Our tests have redundant code
17Fixtures
- In generic xUnit, a test fixture is all the
things that must be in place in order to run a
test and expect a particular outcome. (from
wikipedia) - we typically have
- setUp selector to do any initialization for a
test - tearDown selector to do the cleanup
- NOTE Fixtures are not constructors/destructors,
each test case gets its own copy of them (in
contrast to same constructor/destructor being run
for all methods of a class) to say the least.
18Fixtures, lets apply
- So, lets extract the duplicate code to setUp and
tearDown selectors - both of our test cases require a
TemperatureCalculator instance, so we can make it
a member variable - the header file is now
19Fixtures, implementation
20New Feature
- so far so good, but heres a new feature
- calculate the boiling point of water in a given
city based on barometric pressure
Formula for calculation is
Boiling Point of Water 49.161 Ln(Barometric
Pressure) 44.932
NOTE Formula returns boiling point in Fahrenheit
scale, for simplicity, I am not going to convert
it to Kelvin
21Yet another test
- so if the barometric pressure in Denver, Colorado
is currently 24.896 inches of Mercury, then the
boiling point of water is approximately 202
degrees Fahrenheit
22How to implement the feature?
- Okay, so may be we can code boilingPointOfWaterInC
ity such that it looks up the barometric
pressures from AccuWeather.com over the internet,
right?
- We can implement it like that but in that case
our test case would only pass if the current
barometric pressure in Denver is exactly 24.896
inches of Mercury
- We should probably decouple weather lookup
service from our TemperatureCalculator
23Design Feedback from TDD
- So, may be we can make a protocol called
WeatherLookupService, and we make our test case
class conform to this protocol. The
implementation, however, returns values
appropriate for our test cases?
- Heres an informal WeatherLookupService protocol
NOTE WeatherLookupService protocol is defined in
TemperatureCalculator.h
24TemperatureCalculator updated
- heres the updated header file
25TemperatureCalculator updated
- corresponding implementation is
26Test case needs an update too!
- Our test case class (in this case) acts as a Mock
object by the way.
- A Mock object is an object that mimics the
behavior of a real object to simplify testing
27Thats it!
- Build the RunAllTests target, all tests should
pass
- Heres what we covered today
- Configuring Google Toolbox for Mac (GTM)
- Write simple unit tests
- Use Fixtures
- Using Mock Objects to simplify testing
28Fruit for Thought
- Heres what we did not cover
- GTM Log Tracking
- GTM UI Unit Testing
- GTM HTTP Unit Testing
- GTM Code Coverage Analysis
- GTMDebugSelectorValidation
- GTMMethodCheck
29Notes
- Unit Tests cannot be run while iPhone Simulator
is running, if you do, you may receive an error
like this - Couldn't register PurpleSystemEventPort with the
bootstrap server. Error unknown error code. This
generally means that another instance of this
process was already running or is hung in the
debugger. - GTM has several assert macros, find them inside
google-toolbox-for-mac/UnitTesting/GTMSenTestCase.
h - GTM does not support binding unit testing on the
iPhone as NSBinding is not supported on the
iPhone.
30Resources
- GTM http//code.google.com/p/google-toolbox-for-m
ac/ (make sure to check out the wiki pages as
well) - Unit Testing with OCUnit http//developer.apple.c
om/tools/unittest.html - TDD for Games http//gamesfromwithin.com/?p50
- Jeff on Games http//www.jeffongames.com/categoy/
programming/unit-testing/ - Book Beck, Kent, Test Driven Development By
Example. Addison-Wesley, 2002
31Questions?
- NOTE Zambeel Resource Folder smb//zambeel/learn
ing/tdd/