Unit Testing with iOS
Have you ever developed in... <ul><ul><li>Ruby on Rails </li></ul></ul><ul><ul><li>PHP on Symfony </li></ul></ul><ul><ul><...
Unfortunately... <ul><ul><li>&quot;Objective-C on Cocoa Touch&quot; didn't make the list. </li></ul></ul>
Why test in the first place? <ul><ul><li>You can't write a test case until you know what &quot;good output&quot; and &quot...
Unit testing in Objective-C <ul><ul><li>Functional tests are a bit painful yet (I feel) in Objective-C / Cocoa Touch - you...
Unit testing frameworks provide... <ul><ul><li>Setup/teardown helpers run before each test </li></ul></ul><ul><ul><li>Asse...
Choosing a unit testing framework... <ul><ul><li>You have 2 choices: </li></ul></ul><ul><ul><ul><li>GHUnit (on GitHub) </l...
More details on OCUnit... <ul><ul><li>When you tick &quot;Use Unit Testing&quot; on the New Project template wizard, the s...
More details on GHUnit... <ul><ul><li>Handier macros & test class helper methods than OCUnit </li></ul></ul><ul><ul><li>Ca...
Whichever you choose... <ul><ul><li>They will both get the job done, and they are both   so much better  than having no u...
Let's write some tests... <ul><li>There are 2 times to write unit tests: </li></ul><ul><ul><li>Before developing a new fea...
What does a unit test look like? <ul><li>// MyTest.m (I roll .h into this) </li></ul><ul><li>- (void) setUp { } </li></ul>...
I use setUp and tearDown for this... <ul><li>@interface LWEFormViewTest { </li></ul><ul><li>   LWEFormView _testObject; } ...
...which helps me focus on tests: <ul><li>- (void) testTextFieldAdd </li></ul><ul><li>{ </li></ul><ul><li>   UITextField *...
Assertion macros finish off the test <ul><li>- (void) testTextFieldAdd </li></ul><ul><li>{ </li></ul><ul><li>   UITextFiel...
GHUnit & OCUnit macros <ul><li>   GHUnit:  </li></ul><ul><ul><li>GHAssertTrue </li></ul></ul><ul><ul><li>GHAssertEqualObje...
Unit tests you should always write <ul><ul><li>Incorrect object types </li></ul></ul><ul><ul><li>Out-of-bounds values </li...
Q+A <ul><ul><li>Interested to hear everyone's experiences with testing on iOS </li></ul></ul>
Upcoming SlideShare
Loading in …5
×

Unit Testing in iOS

8,143 views

Published on

Published in: Technology, Education

Unit Testing in iOS

  1. 1. Unit Testing with iOS
  2. 2. Have you ever developed in... <ul><ul><li>Ruby on Rails </li></ul></ul><ul><ul><li>PHP on Symfony </li></ul></ul><ul><ul><li>PHP on Zend </li></ul></ul><ul><ul><li>Python on Django </li></ul></ul><ul><ul><li>Java on J2EE </li></ul></ul><ul><li>All of these languages / frameworks make it easy to write/run: </li></ul><ul><ul><li>Unit tests </li></ul></ul><ul><ul><li>Functional tests </li></ul></ul><ul><ul><li>Integration tests </li></ul></ul>
  3. 3. Unfortunately... <ul><ul><li>&quot;Objective-C on Cocoa Touch&quot; didn't make the list. </li></ul></ul>
  4. 4. Why test in the first place? <ul><ul><li>You can't write a test case until you know what &quot;good output&quot; and &quot;bad output&quot; look like: writing a test case forces you to define the problem . </li></ul></ul><ul><ul><li>And, if you write test cases before you write production code, you are not emotionally attached to an implementation -- if you discover a mistake, you're likely to address it. </li></ul></ul>
  5. 5. Unit testing in Objective-C <ul><ul><li>Functional tests are a bit painful yet (I feel) in Objective-C / Cocoa Touch - you have to write Javascript commands </li></ul></ul><ul><ul><li>Let's focus on unit testing only today (larger &quot;units&quot; can start to act as functional tests). </li></ul></ul>
  6. 6. Unit testing frameworks provide... <ul><ul><li>Setup/teardown helpers run before each test </li></ul></ul><ul><ul><li>Assertion macros like: </li></ul></ul><ul><ul><ul><li>STAssertTrue(NO,@&quot;I am a complete failure&quot;); </li></ul></ul></ul><ul><ul><ul><li>STAssertEqual(foo,bar,@&quot;foo should = bar&quot;); </li></ul></ul></ul><ul><ul><li>A test runner than runs all of, or a subset of, your unit test cases & reports the results. </li></ul></ul>
  7. 7. Choosing a unit testing framework... <ul><ul><li>You have 2 choices: </li></ul></ul><ul><ul><ul><li>GHUnit (on GitHub) </li></ul></ul></ul><ul><ul><ul><li>OCUnit (built into Xcode) </li></ul></ul></ul><ul><ul><li>I spent a long time 1 considering the pros and cons of each, but if you are: </li></ul></ul><ul><ul><ul><li>Writing a new project </li></ul></ul></ul><ul><ul><ul><li>Won't have hundreds of test cases </li></ul></ul></ul><ul><ul><ul><li>Are using Xcode 4 </li></ul></ul></ul><ul><li>     ... then I argue you should probably choose OCUnit . </li></ul><ul><li>1 Approximately 10 hours on a transpacific flight </li></ul>
  8. 8. More details on OCUnit... <ul><ul><li>When you tick &quot;Use Unit Testing&quot; on the New Project template wizard, the set up is already done </li></ul></ul><ul><ul><li>⌘ U  is all you need to press to run your tests </li></ul></ul><ul><ul><li>Does not have the -setUpClass and -tearDownClass helpers </li></ul></ul><ul><ul><li>Does not allow you to run unit tests individually, must run entire test suite (some MAY argue that this is a &quot;feature&quot;) </li></ul></ul>
  9. 9. More details on GHUnit... <ul><ul><li>Handier macros & test class helper methods than OCUnit </li></ul></ul><ul><ul><li>Can run a single test (good for debugging if you have many tests) </li></ul></ul><ul><ul><li>Much sexier log output than OCUnit </li></ul></ul><ul><ul><li>Not built into Xcode 4, you have to set it up as a separate target and build & link its framework </li></ul></ul><ul><ul><li>More time-consuming to run tests </li></ul></ul><ul><ul><li>Runs in the Simulator or on the device as an actual target, with its own UI </li></ul></ul>
  10. 10. Whichever you choose... <ul><ul><li>They will both get the job done, and they are both   so much better  than having no unit tests at all. </li></ul></ul><ul><ul><li>OK, so all set up?  If you need help on GHUnit, see my blog post on the subject: http://longweekendmobile.com/2011/02/23/tdd-best-practices-testing-in-ios4-with-ghunit-part-1/ </li></ul></ul>
  11. 11. Let's write some tests... <ul><li>There are 2 times to write unit tests: </li></ul><ul><ul><li>Before developing a new feature (wow, you TDD stud) </li></ul></ul><ul><ul><li>When a section of code is: </li></ul></ul><ul><ul><ul><li>Buggy - doesn't work how you expect </li></ul></ul></ul><ul><ul><ul><li>Fragile - seems to break all the time </li></ul></ul></ul><ul><ul><ul><li>Coupled - seems to break all the time when you change things elsewhere, and in non-obvious ways* </li></ul></ul></ul><ul><li>* Usually this type of test writing is done   after  a bug by such code is found, but also can be done before a major refactor.  Or both.  Unit tests also allow you to  refactor mercilessly,  which is a good habit to be in. </li></ul>
  12. 12. What does a unit test look like? <ul><li>// MyTest.m (I roll .h into this) </li></ul><ul><li>- (void) setUp { } </li></ul><ul><li>- (void) tearDown { </li></ul><ul><li>} </li></ul><ul><li>- (void) testSomething { </li></ul><ul><li>} </li></ul><ul><li>- (void) testAnotherThing { </li></ul><ul><li>} </li></ul>
  13. 13. I use setUp and tearDown for this... <ul><li>@interface LWEFormViewTest { </li></ul><ul><li>  LWEFormView _testObject; } </li></ul><ul><li>- (void) setUp { </li></ul><ul><li>   _testObject = [[LWEFormView alloc]     </li></ul><ul><li>                      initWithFrame:CGRectZero]; </li></ul><ul><li>} </li></ul><ul><li>- (void) tearDown { </li></ul><ul><li>   [_testObject release]; </li></ul><ul><li>  _testObject = nil; </li></ul><ul><li>} </li></ul>
  14. 14. ...which helps me focus on tests: <ul><li>- (void) testTextFieldAdd </li></ul><ul><li>{ </li></ul><ul><li>  UITextField *aField = [[UITextField alloc] init]; </li></ul><ul><li>  aField.tag = 1; </li></ul><ul><li>  [_testObject addSubview:aField]; </li></ul><ul><li>   int numForms = [[_testObject formOrder] count]; </li></ul><ul><li>  // Assertions go here </li></ul><ul><li>  [aField release]; </li></ul><ul><li>} </li></ul>
  15. 15. Assertion macros finish off the test <ul><li>- (void) testTextFieldAdd </li></ul><ul><li>{ </li></ul><ul><li>  UITextField *aField = [[UITextField alloc] init]; </li></ul><ul><li>  aField.tag = 1; </li></ul><ul><li>  [_testObject addSubview:aField]; </li></ul><ul><li>   int numForms = [[_testObject formOrder] count]; </li></ul><ul><li>  GHAssertTrue((numForms == 1), </li></ul><ul><li>             @&quot;We added an object, why wasn't it showing up?&quot;); </li></ul><ul><li>  id<NSObject> lastObj = [[_testObject formOrder] lastObject]; </li></ul><ul><li>  GHAssertEqualObjects(lastObj,aField, </li></ul><ul><li>            @&quot;Why did a different one come back?&quot;); </li></ul><ul><li>  [aField release]; </li></ul><ul><li>} </li></ul>
  16. 16. GHUnit & OCUnit macros <ul><li>  GHUnit:  </li></ul><ul><ul><li>GHAssertTrue </li></ul></ul><ul><ul><li>GHAssertEqualObjects </li></ul></ul><ul><ul><li>... many more </li></ul></ul><ul><li>  OCUnit: </li></ul><ul><ul><li>STAssertTrue </li></ul></ul><ul><ul><li>STAssertEquals </li></ul></ul><ul><ul><li>... many more </li></ul></ul>
  17. 17. Unit tests you should always write <ul><ul><li>Incorrect object types </li></ul></ul><ul><ul><li>Out-of-bounds values </li></ul></ul><ul><ul><li>Boundary values </li></ul></ul><ul><ul><li>Expected values </li></ul></ul><ul><ul><li>Using loops to stress test... but maybe not unit </li></ul></ul>
  18. 18. Q+A <ul><ul><li>Interested to hear everyone's experiences with testing on iOS </li></ul></ul>

×