My unit test environment for Objective-C

0d04162c7a3c2907c059a06dbcd23cf4?s=47 tokorom
December 21, 2013

My unit test environment for Objective-C

My unit test environment for Objective-C.
- The test for asynchronous processes
- Matcher
- CUI & Guard
- Coverage

0d04162c7a3c2907c059a06dbcd23cf4?s=128

tokorom

December 21, 2013
Tweet

Transcript

  1. ࠷ۙɺςετίʔυ؀ڥ ͲΜͳ͔Μ͡Ͱ͔͢ʁ ΅͘͸͜Μͳ͔Μ͡Ͱ͢ɻ ॴ ༑ଠ @tokorom iOS App Programer These

    are “not” confidential sessions—please “not” refrain from blogging, or taking pictures Yokohama iPhone Developers #14
  2. Agenda • ඇಉظॲཧͷςετ • matcher •ͦͷଞϥΠϒϥϦ • CUI & Guard

    •ίʔυΧόϨοδ •CI
  3. લఏ৚݅ • ඪ४ͷXCTestϑϨʔϜϫʔΫΛ࢖͏͜ͱ • Command + U Ͱςετ࣮ߦ & Xcode୯ମͰ΋

    ςετ݁Ռ͕֬ೝͰ͖Δ͜ͱ • ͜ͷൣғͰ֎෦ϥΠϒϥϦͷར༻Λڐ༰
  4. ඇಉظॲཧͷςετ

  5. GHUnit - (void)testExample { [self prepare]; __block NSString *response =

    nil; [self requestGetAsyncronous:^(id res, NSError *error) { response = res; if (error) { [self notify:kGHUnitWaitStatusSuccess]; } else { [self notify:kGHUnitWaitStatusFailure]; } }]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.0]; XCTAssertEqualObjects(response, @“OK!”); }
  6. GHUnit • GHAsyncTestCase •̎೥લ͘Β͍͸σϑΝΫτελϯμʔυ • ͦͷࠒ͔Β͋·ΓUpdate͞Εͣ࠷৽ͷXcode & iOSͰ࢖͑ͳ͍ঢ়گ͕ଓ͘͜ͱ΋͋ͬͨ •ݱࡏ͸ x2on

    ͞Μ͕͕Μ͹ͬͯXcode 5 & iOS 7 Ͱ΋ಈ͘໛༷
  7. ΦϨΦϨAsyncTestCase • ݱࡏͷσϑΝΫτʁ • ࣗ෼΋͍ͭઌ೔·ͰίϨ •ϝϦοτ •GHUnitͱಉ͡ײ֮Ͱ࢖͑Δ • σϝϦοτ •ΦϨΦϨͰ͍͍ͷ͔ʁ

    • ਌Ϋϥε͕ݶఆ͞ΕΔͷ͕௧͍ •Rubyist͔Βμα͍ͬͯݴΘΕͨ
  8. will @ Expecta - (void)testExample { __block NSString *response =

    nil; [self requestGetAsyncronous:^(id res, NSError *error) { response = res; }]; expect(response).will.equal(@“OK!”); }
  9. will @ Expecta •ྑ͍ͱ͜Ζ •ίʔυྔ͕ܶతʹݮΔ •਌Ϋϥε͕റΒΕͳ͍ •Rubyist΋ೲಘ •ѱ͍ͱ͜Ζ •matcherʹΑͬͯ͸ରԠͯ͠ͳ͍ •match͠ͳ͍ͱλΠϜΞ΢τ·Ͱ଴ͭ

    •matcher͕࿈ଓ͢Δ৔߹Ͳ͏ॻ͘?໰୊
  10. RubyMotion it 'should be xxx' do some_method_with_block {|some_data| @data =

    some_data resume } wait_max 1.0 do @data.should.equal ‘OK!’ end end
  11. ͜͏͍͏ͷ͕ཧ૝ •RubyMotionελΠϧͷObjective-C൛ •wait & resume Ͱγϯϓϧʹ •wait΋ExpectaΈ͍ͨʹλΠϜΞ΢τઃఆΛলུՄ •match͠ͳͯ͘΋଴ͨ͞Εͳ͍

  12. ࡞ͬͨΑʂ - (void)testExample { __block NSString *response = nil; [self

    requestGetAsyncronous:^(id res, NSError *error) { response = res; RESUME; }]; WAIT; XCTAssertEqualObjects(response, @“OK!”); }
  13. TKRGuard •ձࣾͰطʹ࣮༻Խ •waitͷೖΕࢠ΋Մೳ •GHUnitͷΑ͏ͳnotifyϞʔυ΋࣮૷༧ఆ •Macroݏ͍ͳਓ͸SHORTHANDϞʔυΛOffʹ͠ ͯͶ https://github.com/tokorom/TKRGuard

  14. matcher

  15. matcher •matcherʹ͍ͭͯ͸XCTAssertsͰ΋ͳΜͱ͔ͳ Γͦ͏ •΅͘͸Expecta͕޷ΈͰ͢

  16. XCTAsserts int i1 = 100; NSInteger i2 = 100; NSNumber

    *number = @100; NSString *string = @"OK"; ! XCTAssertEqual(i1, 100); XCTAssertEqual((int)i2, 100); XCTAssertEqualObjects(number, @100); XCTAssertEqualObjects(string, @"OK");
  17. OCHamcrest int i1 = 100; NSInteger i2 = 100; NSNumber

    *number = @100; NSString *string = @"OK"; assertThatInt(i1, equalToInt(100)); assertThatInteger(i2, equalToInteger(100)); assertThat(number, equalTo(@100)); assertThat(string, equalTo(@"OK"));
  18. Expecta int i1 = 100; NSInteger i2 = 100; NSNumber

    *number = @100; NSString *string = @"OK"; expect(i1).to.equal(100); expect(i2).to.equal(100); expect(number).to.equal(@100); expect(string).to.equal(@"OK");
  19. ςετࣦഊ࣌ͷΨΠυ • XCTAsserts •("OK") is not equal to ("NG") •(([number

    isKindOfClass:[NSString class]]) is true) failed • OCHamcrest •Expected "NG", but was "OK" •Expected an instance of NSString, but was __NSCFNumber instance <100> •Expecta •expected: NG, got: OK •expected: a kind of NSString, got: an instance of __NSCFNumber, which is not a kind of NSString
  20. ͦͷଞϥΠϒϥϦ

  21. ͦͷଞ࢖͍ͬͯΔϥΠϒϥϦ • OCMock •ಛఆͷςετͷͱ͖ʹڧ੍తʹΤϥʔΛฦ ͍ͨ͠ͱ͔ݩͷιʔεΛ͍͡Βͣʹςετ ༻ʹڍಈΛม͑ΒΕΔ •andDo ͱ͔ศརʂ • OHHTTPStubs

    •࣮ࡍʹ௨৴ͤͣ͞ʹςετ༻ͷσʔλʹࠩ ͠ସ͑Δͷ͕؆୯
  22. CUI & Guard

  23. Xcode 4.x xcodebuild \ -project $(PROJECT) \ -target $(TEST_TARGET) \

    -sdk iphonesimulator \ -configuration Debug \ TEST_AFTER_BUILD=YES \ TEST_HOST=
  24. Xcode 5.x xcodebuild test \ -scheme $(SCHEME) \ -destination $(DESTINATION)

  25. Guard

  26. Guard require 'guard/plugin' ! module ::Guard class InlineGuard < ::Guard::Plugin

    SCHEME = 'Tests' DESTINATION = 'platform=iOS Simulator,name=iPhone Retina (3.5-inch),OS=7.0' COMMAND = "xcodebuild test -scheme #{SCHEME} -destination '#{DESTINATION}'" def run_all system(COMMAND) end def run_on_changes(paths) run_all end end end ! guard :inline_guard do watch /.*\.[mh]$/ end
  27. xcpretty (xctoolېࢭલఏͰʣ

  28. xcpretty gem install xcpretty ! xcodebuild test \ -scheme $(SCHEME)

    \ -destination $(DESTINATION) \ | xcpretty -c
  29. ฤूதͷςετ͚࣮ͩߦ͍ͨ͠ • xctoolΛ࢖͑͹Ͱ͖Δ͚Ͳ… •xcodebuild୯ମͰ͸Ͱ͖ͳ͍ͬΆ͍ •xctestίϚϯυͰ࣮ݱՄೳͬΆ͍͕·ͩௐࠪத •xctest·Ͱͷͭͳ͗ͱͯ͠xcodebuild୯ମͰ΋ Ͱ͖ΔϥΠϒϥϦΛ࡞ͬͨ

  30. TKRSpecificTest xcodebuild test \ -scheme $(SCHEME) \ -destination $(DESTINATION) \

    GCC_PREPROCESSOR_DEFINITIONS='TEST_ONLY=\"TestCase\"'
  31. ίʔυΧόϨοδ

  32. ίʔυΧόϨοδ

  33. xxx.gcno & xxx.gcda GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES \ GCC_GENERATE_TEST_COVERAGE_FILES=YES !

  34. Xcode 5 & iOS 7 •gcda͕ग़ྗ͞Εͳ͍ʂʁ

  35. Xcode 5 & iOS 7 extern void __gcov_flush(void); __gcov_flush();

  36. XCTestObserver

  37. XCTestObserver NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:@"XCTestLog,XXXObserver" forKey:XCTestObserverClassKey]; [defaults

    synchronize];
  38. XCTestObserver @interface XXXObserver : XCTestObserver @end ! @implementation XXXObserver -

    (void)stopObserving { [super stopObserving]; extern void __gcov_flush(void); __gcov_flush(); } ! @end
  39. ՝୊ • ී௨ʹ΍Δͱ gcda ͕ग़ྗ͞Εͣ •_gcov_flush() ͢Δͱ gcno ͕ग़ྗ͞Εͣ •ݱঢ়ɺී௨ʹtestɺ_gcov_flush()෇͖Ͱtestͷ̎

    ஈߏ੒Ͱ΍͍ͬͯΔʢແବʣ
  40. CI

  41. σʔλͷ഑෍ • ͜ͷKeynote •=> Speaker DeckʹΞοϓ͠·͢ • αϯϓϧίʔυ •https://github.com/tokorom/CompareObjcMatcher •https://github.com/tokorom/

    ReplaceImageCategoryForXcode •https://github.com/tokorom/TKRGuard •https://github.com/tokorom/TKRSpecificTest !
  42. More Information Yuta ToKoRo! iOS App Programer! @tokorom! ! http://www.tokoro.me/