Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing in iOS

Testing in iOS

Mobile Optimized 2013
http://mo.dev.by

Victor Ilyukevich

May 31, 2013
Tweet

More Decks by Victor Ilyukevich

Other Decks in Programming

Transcript

  1. Why do I need to spend time writing tests? it

    reduces bugs it helps to produce good code it proves your code is working as supposed to tests are documentation to your code it makes easy to maintain your code ...
  2. Tuneup JS http://www.tuneupjs.org test("Login screen", function(target, app) { var window

    = app.mainWindow(); // tap the left button in the navigation bar window.navigationBars()[0].leftButton().tap(); // assert that the app has navigated into a sub-view controller assertEquals("Settings", window.navigationBars()[0].value()); });
  3. mechanic.js https://github.com/jaykz52/mechanic //  all  UIAStaticText  elements  directly  descended  from  a

      tabbar $('tabbar  >  text'); //  all  buttons  inside  the  window  named  'Main' $('window[name=Main]  button') //  the  text  field  with  a  value  of  'Search' $('textfield[value=Search]') //  all  buttons  plus  a  specific  element  by  name $('button,  #Continue')
  4. Bwoken adds easy commands to run tests from CLI $

     rake $  rake  compile  &&  rake  test equals to:
  5. Bwoken adds easy commands to run tests from CLI $

     rake $  rake  compile  &&  rake  test $  SIMULATOR=true  rake
  6. Bwoken adds easy commands to run tests from CLI $

     rake $  rake  compile  &&  rake  test $  SIMULATOR=true  rake $  RUN=iphone/focused_test  rake
  7. Bwoken adds easy commands to run tests from CLI allows

    you to run tests with CoffeeScript
  8. Bwoken adds easy commands to run tests from CLI allows

    you to run tests with CoffeeScript fill = (container, liquid = "coffee") -> "Filling the #{container} with #{liquid}..."
  9. Bwoken adds easy commands to run tests from CLI allows

    you to run tests with CoffeeScript fill = (container, liquid = "coffee") -> "Filling the #{container} with #{liquid}..." var fill; fill = function(container, liquid) { if (liquid == null) { liquid = "coffee"; } return "Filling the " + container + " with " + liquid + "..."; };
  10. Bwoken adds easy commands to run tests from CLI allows

    you to run tests with CoffeeScript http://coffeescript.org
  11. UIAutomation + Tuneup JS + Bwoken + CoffeeScript #import  "../helpers/Caremobile.js"

      Caremobile.resetAppState() SignInScreen.signIn('testuser',  'testpass')   test  'Caregiver  adds  a  beloved',  (target,  app)  -­‐>    name  =  'Kurt  Cobain'    BelovedsScreen.tapAddButton()    ProfileScreen.setFields({  'full  name':  name  })    ProfileScreen.tapSaveButton()    BelovedsScreen.assertBeloved({  regex:  new  RegExp(name,  "g")  })   test  'Caregiver  edits  a  beloved',  (target,  app)  -­‐>    ...
  12. UIAutomation + Tuneup JS + Bwoken + CoffeeScript class  BelovedsScreenClass

     extends  BaseListScreen      assertBeloved:  (args)  -­‐>        @assertCell  args      belovedsList:  -­‐>        Caremobile.window().tableViews()['List  of  loved  ones']      tapBelovedNamed:  (name)  -­‐>        @belovedsList().cells()[name].tap()     BelovedsScreen  =  new  BelovedsScreenClass
  13. UIAutomation + Tuneup JS + Bwoken + CoffeeScript Passing custom

    params to the app. https://github.com/carezone/bwoken/commit/195f2f9
  14. UIAutomation + Tuneup JS + Bwoken + CoffeeScript Passing custom

    params to the app. desc  "Run  tests" task  :run_tests  do    ENV['INSTRUMENTS']  =  "-­‐e  TEST_MODE  1"    Rake::Task[:default].invoke end Add a new task to your Rakefile: https://github.com/carezone/bwoken/commit/195f2f9
  15. UIAutomation + Tuneup JS + Bwoken + CoffeeScript Passing custom

    params to the app. BOOL  IsTestMode()  {    return  (getenv("TEST_MODE")  !=  nil); } https://github.com/carezone/bwoken/commit/195f2f9
  16. SetTestingKit.framework @implementation  MyAppTests   -­‐  (void)setUp  {      

     [super  setUp];        //  Set-­‐up  code  here. }   -­‐  (void)tearDown  {        //  Tear-­‐down  code  here.        [super  tearDown]; }   -­‐  (void)testExample  {        STFail(@"Unit  tests  are  not  implemented  yet  in  MyAppTests"); }   @end
  17. Why do I like Kiwi. expectations [[subject  should]  beTrue]; [[subject

     should]  equal:(id)anObject]; [[subject  should]  beLessThan:(id)aValue]; [[@"Hello,  world!"  should]  containString:@"world"]; [[subject  should]  beKindOfClass:(Class)aClass]; [[subject  should]  haveCountOf:(NSUInteger)aCount];   NSArray  *array  =  [NSArray  arrayWithObject:@"foo"]; [[array  should]  have:1]  item];   [[subject  should]  receive:(SEL)aSelector  andReturn:(id)aValue]; [[theBlock(^{  ...  })  should]  raise];
  18. Why do I like Kiwi. expectations ‘describe’, ‘context’, ‘before each’,

    ‘before all, ‘after each’, ‘after all’ blocks
  19. Why do I like Kiwi. expectations ‘describe’, ‘context’, ‘before each’,

    ‘before all, ‘after each’, ‘after all’ blocks mocks objects that imitate a class, or look like they conform a protocol
  20. Why do I like Kiwi. expectations ‘describe’, ‘context’, ‘before each’,

    ‘before all, ‘after each’, ‘after all’ blocks mocks objects that imitate a class, or look like they conform a protocol stubs return canned responses on method calls
  21. Why do I like Kiwi. id  mock  =  [Animal  mock];

    [[mock  should]  beMemberOfClass:[Animal  class]];   [mock  stub:@selector(species)  andReturn:@"P.  tigris"]; [[mock.species  should]  equal:@"P.  tigris"]; [Cruiser  stub:@selector(classification)  andReturn:@"Not  a  moon"]; [[[Cruiser  classification]  should]  equal:@"Not  a  moon"];
  22. Got it. Show me real code! #import  <Kiwi/Kiwi.h> #import  "Matrix.h"

    SPEC_BEGIN(MatrixSpec)    describe(@"Matrix",  ^{        __block  Matrix  *matrix  =  nil;        context(@"initialized  with  size  of  3",  ^{            beforeEach(^{                matrix  =  [[Matrix  alloc]  initWithSize:3];            });            it(@"has  size  of  3",  ^{                [[theValue(matrix.size)  should]  equal:theValue(3)];            });            context(@"sets  value  3  to  row  2  column  1",  ^{                beforeEach(^{                    [matrix  setValue:@3  forRow:2  column:1];                }); ...            });        });    }); SPEC_END
  23. Got it. Show me real code! describe(@"CalendarEvent",  ^{    __block

     CalendarEvent  *event  =  nil;    beforeEach(^{        NSManagedObjectContext  *context  =  [NSManagedObjectContext                                                          makeMainQueueContext];        event  =  [CalendarEvent  insertIntoContext:context];    });        context(@"when  current  time  is  23:44",  ^{        it(@"starts  at  00:00",  ^{            [[NSDate  stubAndReturn:[NSDate  dateFromYear:2012                  month:1  day:23  hour:23  minute:44]]  date];            [event  setupDefaultDates];            [[event.startsAt  should]  equal:[NSDate  dateFromYear:2012                                  month:1  day:24  hour:0  minute:0]];        });    }); });
  24. Cedar a bunch of matchers stubs and mocks describe and

    context blocks before each and after each blocks pending specs focused specs reporters https://github.com/pivotal/cedar
  25. -­‐  (void)testAuthorizationHeaderWithInvalidUsernamePassword  {        [Expecta  setAsynchronousTestTimeout:5.0];    

               __block  NSHTTPURLResponse  *response  =  nil;        [self.client  getPath:@"/basic-­‐auth/username/password"                            parameters:nil                                  success:NULL                                  failure:^(AFHTTPRequestOperation  *operation,  NSError   *error)  {                response  =  operation.response;        }];                expect(response.statusCode).will.equal(401); } OCMock + Expecta
  26. -­‐  (void)testAuthorizationHeaderWithInvalidUsernamePassword  {        [Expecta  setAsynchronousTestTimeout:5.0];    

               __block  NSHTTPURLResponse  *response  =  nil;        [self.client  getPath:@"/basic-­‐auth/username/password"                            parameters:nil                                  success:NULL                                  failure:^(AFHTTPRequestOperation  *operation,  NSError   *error)  {                response  =  operation.response;        }];                expect(response.statusCode).will.equal(401); } OCMock + Expecta https://github.com/AFNetworking/AFNetworking
  27. xcodebuild $  xcodebuild  -­‐workspace  MyApp.xcworkspace  \        

                     -­‐scheme  MyScheme  \                          -­‐sdk  iphonesimulator  \                          -­‐configuration  Release  \                          build
  28. xcodebuild desc  "Run  unit  tests" task  :unittest  do    kill_simulator

         cmd  =  "xcodebuild  -­‐workspace  #{WORKSPACE_NAME}.xcworkspace  \                                        -­‐scheme  #{SCHEME_NAME}  \                                        -­‐sdk  iphonesimulator  \                                        -­‐configuration  Release                                          RUN_UNIT_TEST_WITH_IOS_SIM=YES  \                                        build"    stdout  =  TestOutput.new(STDOUT)    stderr  =  TestOutput.new(STDERR)    status  =  Open4.spawn(cmd,                                              :stdout  =>  stdout,                                              :stderr  =>  stderr,                                              :status  =>  true)    exit  status.exitstatus end
  29. xctool $  brew  install  xctool $  xctool  -­‐workspace  App.xcworkspace\  

                   -­‐scheme  App\                  test
  30. Travis CI Provides hosted CI service free for open source

    (public repo) paid for private repositories A hosted continuous integration service for the open source community
  31. Travis CI A hosted continuous integration service for the open

    source community language:  objective-­‐c before_install:    -­‐  brew  update    -­‐  brew  install  xctool script:  xctool  test Setup for open source project Add .travis.yml file at root of your repository
  32. Travis CI A hosted continuous integration service for the open

    source community Login at http://travis-ci.org and enable it Add .travis.yml file at root of your repository Setup for open source project
  33. Travis CI A hosted continuous integration service for the open

    source community Login at http://travis-ci.org and enable it Add .travis.yml file at root of your repository Setup for open source project Add nice status picture to your README