Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

takasek iOS Developer @takasek OSS ActionClosurable Notifwift౳ 2

Slide 3

Slide 3 text

લճ·Ͱͷ ͋Β͢͡ 3

Slide 4

Slide 4 text

iOS Test Night #3 ʹͯൃද 4

Slide 5

Slide 5 text

5

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

! 12

Slide 13

Slide 13 text

ςετॻ͖ͨ͘ͳ͍ཧ༝ᶄ ෛ࠴ʹͳΓ΍͍͢ "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

Slide 14

Slide 14 text

14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

doctest 17

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

doctest αϯϓϧίʔυ(python) def hoge(): """ >>> hoge() 'Hello World' """ return "Hello world" if __name__ == "__main__": import doctest doctest.testmod() 19

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

doctest ݕূ݁Ռ def hoge(): """ >>> hoge() 'Hello World' """ return "Hello world"ɹ! w ͕খจࣈʹͳͬͯΔʂʂ if __name__ == "__main__": import doctest doctest.testmod() 21

Slide 22

Slide 22 text

ର࿩؀ڥΛ ͦͷ··ίϐϖͨ͠Β ςετʹͳΔͷ ͍͍Ͷ ! 22

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Swift/Xcode΋ doctest తͳ΋ͷ ಋೖͯ͘͠Εͯ΋ ͍͍ͷͰ͸ 26

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

! 28

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

QuickCheck ͱ͸ 3 QuickCheckʢΫΠοΫνΣοΫʣ͸ɺ(...) HaskellͰॻ͔Εͨί ϯϏωʔλϥΠϒϥϦͰ͋Δɻ QuickCheckͰ͸ϓϩάϥϚ͸ؔ਺͕ຬͨ͢΂͖࿦ཧతੑ࣭ΛΞα ʔγϣϯͱͯ͠ॻ͘ɻςετ͸ؔ਺ͷҾ਺ͷܕ͕औΓಘΔ஋Λϥϯ μϜʹؔ਺ʹ༩͑Δ͜ͱͰɺΞαʔγϣϯ͕ࣦഊ͢Δ৚݅Λ୳ͦ͏ ͱࢼΈΔɻ(...) QuickCheck͸௨ৗͷϓϩάϥϜͷςετʹՃ͑ɺ ؔ਺࢓༷ͷࡦఆɺؔ਺͕͢Δ΂͖ڍಈΛυΩϡϝϯτͱͯࣔ͢͠ɺ ίϯύΠϥͷ࣮૷Λςετ͢Δɺͱ͍ͬͨ͜ͱʹ΋༗༻Ͱ͋Δɻ 3 https://ja.wikipedia.org/wiki/QuickCheck 30

Slide 31

Slide 31 text

https://github.com/typelift/SwiftCheck Star΋ଟ͘ɺܧଓͯ͠։ൃ͞Ε͍ͯΔɻΑͦ͞͏ɻ 31

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

૊Έ߹ΘͤͯδΣωϨʔλΛ࡞ͬͯ… let localEmail = allowedLocalCharacters .proliferateNonEmpty .suchThat({ $0[$0.index(before: $0.endIndex)] != "." }) .map { String($0) } let hostname = Gen.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 // "!'[email protected]" emailGen.generate // "46n}ZmEDg760&4L4RR#.Q'b{}[email protected]" 33

Slide 34

Slide 34 text

ςετσʔλΛੜ੒͢ΔArbitraryΛ༻ҙͯ͠ struct ArbitraryEmail : Arbitrary { let email : String static var arbitrary : Gen { return emailGen.map(ArbitraryEmail.init) } } 34

Slide 35

Slide 35 text

ͦͷੑ࣭ΛνΣοΫ property("τοϓϨϕϧυϝΠϯͷμϝͳϝΞυ") <- forAll { (arbitrary : ArbitraryEmail) in ! arbitrary.email.contains(".") }.expectFailure // +++ OK, failed as expected. Proposition: τοϓϨϕϧυϝΠϯͷͳ͍ϝΞυ // Falsifiable (after 1 test): // ArbitraryEmail(email: "{@3.ae") 35

Slide 36

Slide 36 text

ςετσʔλ͕ ൒ࣗಈͰ࡞ΒΕΔͷ ͍͍Ͷ ! 36

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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