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

テストを書かない言い訳をした結果②-負債にならないテストを求めて- / 2170726 #ios_test_night

704056da9a4c4e075ad14479beaebab7?s=47 takasek
July 26, 2017

テストを書かない言い訳をした結果②-負債にならないテストを求めて- / 2170726 #ios_test_night

iOS Test Night #5 - connpass
https://testnight.connpass.com/event/59283/
の発表資料です

---

# 参考リンク

takasek/XCJumpToTests: the script to jump files of Implementation⇄Tests
https://github.com/takasek/XCJumpToTests

typelift/SwiftCheck: QuickCheck for Swift
https://github.com/typelift/SwiftCheck

Property-Based Testing with SwiftCheck
https://news.realm.io/news/tryswift-tj-usiyan-property-based-testing-swiftcheck/

704056da9a4c4e075ad14479beaebab7?s=128

takasek

July 26, 2017
Tweet

Transcript

  1. ςετΛॻ͔ͳ͍ ݴ͍༁Λͨ݁͠Ռᶄ -ෛ࠴ʹͳΒͳ͍ςετΛٻΊͯ- by. 2017/7/26 iOS Test Night #5 1

  2. takasek iOS Developer @takasek OSS ActionClosurable Notifwift౳ 2

  3. લճ·Ͱͷ ͋Β͢͡ 3

  4. iOS Test Night #3 ʹͯൃද 4

  5. 5

  6. ςετॻ͖ͨ ͘ͳ͍ཧ༝ᶃ ςετϑΝΠϧ΁ ͷڑ཭͕ԕ͍ 6

  7. ଓฤൃදͰղܾ (iOS Test Night #4) 7

  8. ςετϑΝΠϧ΁ͷڑ཭͕ԕ͍ͷͳΒ ςετͱ࣮૷ͷڑ཭Λ ͚ۙͮΔεΫϦϓτΛ ࡞Δ! 8

  9. https://github.com/takasek/XCJumpToTests 9

  10. ͜ΕͰ࣮૷ϑΝΠϧͱςετϑΝΠϧΛҰൃͰ੾Γସ͑ΒΕΔʂ 10

  11. ৄ͘͠͸લճൃදͷSpeakerDeckͰ https://speakerdeck.com/takasek/tesutowoshu-kanaiyan-iyi-wositajie- guo-wwwwwww 11

  12. ! 12

  13. ςετॻ͖ͨ͘ͳ͍ཧ༝ᶄ ෛ࠴ʹͳΓ΍͍͢ "The dependencies between packages should be in the

    direction of the stability of the packages. A package should only depend upon packages that are more stable than it is. " 1 ύοέʔδͷґଘؔ܎͸ɺ҆ఆੑͷํ޲ʹґΒͳ͚Ε͹ͳΒͳ͍ɻ ύοέʔδ͸ɺΑΓ҆ఆͨ͠ύοέʔδʹͷΈґଘ͢΂͖ͩɻ ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ- Robert C. Martin 1 Stable Dependencies Principle http://wiki.c2.com/?StableDependenciesPrinciple 13
  14. 14

  15. ࠓճ͸ ͪ͜Βʹ͍ͭͯൃද͠·͢ 15

  16. ڭ͑ͯ΋Βͬͨ "ςετ͕ෛ࠴ʹͳΓ΍͍͢" ໰୊΁ͷղ 4 doctest 4 ϓϩύςΟϕʔεͷςετ 16

  17. doctest 17

  18. doctest ͱ͸ 2 doctest Ϟδϡʔϧ͸ɺର࿩త Python ηογϣϯͷΑ͏ʹݟ͑ΔςΩετΛ୳͠ग़͠ɺη ογϣϯͷ಺༰Λ࣮ߦͯ͠ɺͦ͜ʹॻ͔Ε͍ͯΔ௨Γʹৼ෣͏͔Λௐ΂·͢ɻ doctest ͸Ҏ

    ԼͷΑ͏ͳ༻్ʹΑ͘࢖ΘΕ͍ͯ·͢: 4 Ϟδϡʔϧͷ docstring (υΩϡϝϯςʔγϣϯจࣈྻ) தʹ͋Δର࿩࣮ߦྫͷ͢΂͕ͯ ॻ͔Ε͍ͯΔ௨Γʹಈ࡞͢Δ͔ݕূ͢Δ͜ͱͰɺdocstring ͷ಺༰͕࠷৽͔Ͳ͏͔νΣο Ϋ͢Δɻ 4 ςετϑΝΠϧ΍ςετΦϒδΣΫτதͷର࿩࣮ߦྫ͕ظ଴௨Γʹಈ࡞͢Δ͔Λݕূ͢Δ ͜ͱͰɺճؼςετΛ࣮ݱ͠·͢ɻ 4 ೖग़ྗྫΛ๛෋ʹ࢖ͬͨύοέʔδͷνϡʔτϦΞϧυΩϡϝϯτ͕ॻ͚·͢ɻೖग़ྗྫ ͱղઆจͷͲͪΒʹ஫໨͢Δ͔ʹΑͬͯɺυΩϡϝϯτ͸ʮಡΊΔςετʯʹ΋ʮ࣮ߦͰ ͖ΔυΩϡϝϯτʯʹ΋ͳΓ·͢ɻ 2 https://docs.python.jp/3/library/doctest.html 18
  19. doctest αϯϓϧίʔυ(python) def hoge(): """ >>> hoge() 'Hello World' """

    return "Hello world" if __name__ == "__main__": import doctest doctest.testmod() 19
  20. doctest ࣮ߦ݁Ռ [demo] % python example.py ********************************************************************** File "example.py", line

    4, in __main__.hoge Failed example: hoge() Expected: 'Hello World' Got: 'Hello world' ********************************************************************** 1 items had failures: 1 of 1 in __main__.hoge ***Test Failed*** 1 failures. 20
  21. doctest ݕূ݁Ռ def hoge(): """ >>> hoge() 'Hello World' """

    return "Hello world"ɹ! w ͕খจࣈʹͳͬͯΔʂʂ if __name__ == "__main__": import doctest doctest.testmod() 21
  22. ର࿩؀ڥΛ ͦͷ··ίϐϖͨ͠Β ςετʹͳΔͷ ͍͍Ͷ ! 22

  23. OSSͰSwift༻ͷ doctestπʔϧ ͳ͍͔ͳ…ʁ 23

  24. https://github.com/x007th/SwiftDocTest ! Starͷ਺ɺ3೥લ͔Βߋ৽͕ࢭ·ͬͯΔɺ౳ ؾʹͳΔ… 24

  25. SwiftDocTest ͸͜Μͳײ͡Ͱ࢖͏Β͍͠! /** :test: floor(CGPoint(x:10.9, y:-10.5)) :result: CGPoint(x:10, y:-11) */

    public func floor(value:CGPoint) -> CGPoint { return value.map(floor) } /** :test: ceil(CGPoint(x:10.9, y:-10.5)) :result: CGPoint(x:11, y:-10) */ public func ceil(value:CGPoint) -> CGPoint { return value.map(ceil) } ίϐϖͮ͠Βͦ͏… 25
  26. Swift/Xcode΋ doctest తͳ΋ͷ ಋೖͯ͘͠Εͯ΋ ͍͍ͷͰ͸ 26

  27. Swift/Xcode΋ doctest తͳ΋ͷ ಋೖͯ͘͠Εͯ΋ ͍͍ͷͰ͸ document comments ॆ࣮ͤ͞Α͏ͬͯ API guideline

    Ͱ΋ ݴͬͯΔΜͩ͠ 27
  28. ! 28

  29. ϓϩύςΟϕʔεͷ ςετ (QuickCheck) 29

  30. QuickCheck ͱ͸ 3 QuickCheckʢΫΠοΫνΣοΫʣ͸ɺ(...) HaskellͰॻ͔Εͨί ϯϏωʔλϥΠϒϥϦͰ͋Δɻ QuickCheckͰ͸ϓϩάϥϚ͸ؔ਺͕ຬͨ͢΂͖࿦ཧతੑ࣭ΛΞα ʔγϣϯͱͯ͠ॻ͘ɻςετ͸ؔ਺ͷҾ਺ͷܕ͕औΓಘΔ஋Λϥϯ μϜʹؔ਺ʹ༩͑Δ͜ͱͰɺΞαʔγϣϯ͕ࣦഊ͢Δ৚݅Λ୳ͦ͏ ͱࢼΈΔɻ(...)

    QuickCheck͸௨ৗͷϓϩάϥϜͷςετʹՃ͑ɺ ؔ਺࢓༷ͷࡦఆɺؔ਺͕͢Δ΂͖ڍಈΛυΩϡϝϯτͱͯࣔ͢͠ɺ ίϯύΠϥͷ࣮૷Λςετ͢Δɺͱ͍ͬͨ͜ͱʹ΋༗༻Ͱ͋Δɻ 3 https://ja.wikipedia.org/wiki/QuickCheck 30
  31. https://github.com/typelift/SwiftCheck Star΋ଟ͘ɺܧଓͯ͠։ൃ͞Ε͍ͯΔɻΑͦ͞͏ɻ 31

  32. SwiftCheck ͷ࢖͍ํ ϥϯμϜͳ஋͕ Generate Ͱ͖ΔͷͰ… 32

  33. ૊Έ߹ΘͤͯδΣωϨʔλΛ࡞ͬͯ… let localEmail = allowedLocalCharacters .proliferateNonEmpty .suchThat({ $0[$0.index(before: $0.endIndex)] !=

    "." }) .map { String($0) } let hostname = Gen<Character>.one(of: [ lowerCaseLetters, numeric, Gen.pure("-"), ]).proliferateNonEmpty.map { String($0) } let tld = lowerCaseLetters .proliferateNonEmpty .suchThat({ $0.count > 1 }) .map { String($0) } let emailGen = glue([ localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld ]) emailGen.generate // "q13vS#@s409pwr-plv90-w40--91-.ijtgmvoiljnticlggqlpw" emailGen.generate // "!'wxd8e@d4l5i59-ig0-84r-d-980e2zu-n1.krfqjivizyqahxe" emailGen.generate // "46n}ZmEDg760&4L4RR#.Q'b{}7!@8u---893------s-792--10a3-2h-.sqypnciyqtyod" 33
  34. ςετσʔλΛੜ੒͢ΔArbitraryΛ༻ҙͯ͠ struct ArbitraryEmail : Arbitrary { let email : String

    static var arbitrary : Gen<ArbitraryEmail> { return emailGen.map(ArbitraryEmail.init) } } 34
  35. ͦͷੑ࣭ΛνΣοΫ property("τοϓϨϕϧυϝΠϯͷμϝͳϝΞυ") <- forAll { (arbitrary : ArbitraryEmail) in !

    arbitrary.email.contains(".") }.expectFailure // +++ OK, failed as expected. Proposition: τοϓϨϕϧυϝΠϯͷͳ͍ϝΞυ // Falsifiable (after 1 test): // ArbitraryEmail(email: "{@3.ae") 35
  36. ςετσʔλ͕ ൒ࣗಈͰ࡞ΒΕΔͷ ͍͍Ͷ ! 36

  37. ΋ͬͱৄ͘͠ Property-Based Testing https://news.realm.io/news/tryswift-tj-usiyan-property-based-testing-swiftcheck/ 37

  38. ࠓ೔ͷ·ͱΊ ςετΛॻ͔ͳ͍ݴ͍༁Λ ͨ݁͠Ռ… 38

  39. ࠓ೔ͷ·ͱΊ ςετΛॻ͔ͳ͍ݴ͍༁Λ ͨ݁͠Ռ… ෛ࠴ʹͳΓʹ͍͘ςετํ ๏ͷ஌ݟ͕ू·ͬͨ ! 39