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

Property-based testing with SwiftCheck/PBT-with-SwiftCheck

Property-based testing with SwiftCheck/PBT-with-SwiftCheck

Property-based testing with SwiftCheck

Yusuke Hosonuma

July 27, 2017
Tweet

More Decks by Yusuke Hosonuma

Other Decks in Programming

Transcript

  1. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. iOS Test Night

    #5 2017/07/26(Wed) 
 ࡉপ༞հ@DeNA 1SPQFSUZCBTFEUFTUJOH XJUI4XJGU$IFDL 1
  2. ˙:VTVLF)PTPOVNBʢ!UPCJʣ • ॴଐ ⁃ %F/"48&5άϧʔϓςετج൫νʔϜ • ܦྺ ⁃ J04ΤϯδχΞ⾣೥݄ʹ%F/"48&5άϧʔϓʹ+PJO •

    ීஈͷۀ຿ ⁃ όʔδϣϯɾΞοϓࣗಈݕূγεςϜʢϚεςΟϑʣͷ։ൃ ⁃ ΞϓϦͷςετʹ·ͭΘΔௐ͍ࠪΖ͍Ζ • ଞ ⁃ ͱ͔޷͖Ͱ͢ ࣗݾ঺հ Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 2
  3. ΞδΣϯμ 5 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    1SPQFSUZCBTFEUFTUJOHͱ͸ʁ • 4XJGU$IFDLͱ͸ʁ • ۩ମྫͰݟΔ • ྫ ଍͠ࢉ • ྫ ഑ྻͷ൓స • ༻ޠ • ࣮ફతͳϢʔεέʔε • ·ͱΊ
  4. Property-based testing ͱ͸ʁ 7 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. • ଟ਺ͳϥϯμϜ஋Λ'8ʹࣗಈੜ੒ͤ͞ɺ • ςετର৅ͷੑ࣭ʢ1SPQFSUZʣΛίʔυͰఆٛ͠ɺ • ͦͷੑ࣭͕ഁΒΕΔ஋͕ͳ͍͔ݕূ͢Δ • Ϣχοτςετख๏ͷͭ • ؔ਺ܕݴޠ)BTLFMMͷʮ2VJDL$IFDLʯ͕ݩ
  5. 4XJGU$IFDLͱ͸ʁ 9 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    2VJDL$IFDLͷ4XJGU࣮૷ • IUUQTHJUIVCDPNUZQFMJGU4XJGU$IFDL • 9$5FTUʹ૊ΈࠐΊΔ • 4XJGU[Λ࡞͍ͬͯΔ5ZQF-JGUͷϦϙδτϦ • 4XJGU[ͷςετʹ΋࢖ΘΕͯΔ • .*5MJDFOTF
  6. 10 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. • 1SPQFSUZCBTFEUFTUJOHͱ͸ʁ

    • 4XJGU$IFDLͱ͸ʁ • ۩ମྫͰݟΔ • ྫ ଍͠ࢉ • ྫ ഑ྻͷ൓స • ༻ޠ • ࣮ફతͳϢʔεέʔε • ·ͱΊ
  7. // ϓϩμΫτίʔυ func add(_ x: UInt, _ y: UInt) ->

    UInt { return x + y } // ςετίʔυ func test_add_by_assert() { XCTAssertEqual(add(1, 2), 3) } XCTest Ͱͷ଍͠ࢉͷςετ 13 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 1 + 2 ͷ݁Ռ͸ 3 Ͱ͋Δ͜ͱ • ҰൠతͳY6OJU͕ఏڙ͍ͯ͠Δํ๏ • 2VJDLͳͲͷ#%%ͳ'8΋ຊ࣭తʹ͸ಉ͡
  8. ਤઆ 15 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ̍ʴ̎ʹ̏

    ೖྗ஋ ೖྗ஋ ظ଴஋ ςετର৅ ೖྗ஋ͱظ଴஋͸ɺ ։ൃऀ͕໌ࣔతʹબͿඞཁ͕͋Δ
  9. ςετ༻ͷೖྗ஋ΛબͿٕज़ 17 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ಉ஋෼ׂ๏ • ڥք஋෼ੳ • ΫϥγϑΟέʔγϣϯπϦʔ • 1BJSXJTF๏ • FUDʜ
  10. ςετ༻ͷೖྗ஋ΛબͿٕज़ 18 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ಉ஋෼ׂ๏ • ڥք஋෼ੳ • ΫϥγϑΟέʔγϣϯπϦʔ • 1BJSXJTF๏ • FUDʜ ͲΕ΋֬཰తʹόάͷى͖΍͍͢σʔ λΛ༧ଌͯ͠ɺಛఆ஋ͷΈͰςετ
  11. ଍͠ࢉͷੑ࣭ 21 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ݁߹๏ଇΛຬͨ͢ • Y ZZ Y • Λճ଍ͨ͠΋ͷͱɺΛճ଍ͨ͠΋ͷ͸౳͍͠ • Y  Y  • ʢͪͳΈʹʣҾ͖ࢉ͸݁߹๏ଇΛຬͨ͞ͳ͍ • YZ㱠ZY
  12. ଍͠ࢉͷੑ࣭ 22 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ݁߹๏ଇΛຬͨ͢ • Y ZZ Y • Λճ଍ͨ͠΋ͷͱɺΛճ଍ͨ͠΋ͷ͸౳͍͠ • Y  Y  • ʢͪͳΈʹʣҾ͖ࢉ͸݁߹ੑ͋Γ • YZ㱠ZY ͜ΕΒ͕ͲΜͳೖྗ஋ʹରͯ͠΋ อͨΕΔ΂͖ੑ࣭Ͱ͋Δɺͱߟ͑Δ
  13. 4XJGU$IFDLͰͷ଍͠ࢉͷੑ࣭ςετ 24 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. //

    ;ͭ͏ͷXCTestͱಉ͡Α͏ʹ಄ʹ`test`Λ͚ͭΔ func test_add_property() { // x + y == y + x property("଍͠ࢉ͸݁߹๏ଇΛຬͨ͢") <- forAll { (x: UInt, y: UInt) in return add(x, y) == add(y, x) } // x + 1 + 1 == x + 2 property("1Λ2ճ଍ͨ͠ͷͱɺ2Λ1ճ଍ͨ͠΋ͷ͸౳͍͠") <- forAll { (x: UInt) in return add(add(x, 1), 1) == add(x, 2) } }
  14. 4XJGU$IFDLͰͷ଍͠ࢉͷੑ࣭ςετ 25 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    test_add_property() { // x + y == y + x property("଍͠ࢉ͸݁߹๏ଇΛຬͨ͢") <- forAll { (x: UInt, y: UInt) in return add(x, y) == add(y, x) } } ᶃੑ࣭ͷએݴ
  15. 4XJGU$IFDLͰͷ଍͠ࢉͷੑ࣭ςετ 26 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    test_add_property() { // x + y == y + x property("଍͠ࢉ͸݁߹๏ଇΛຬͨ͢") <- forAll { (x: UInt, y: UInt) in return add(x, y) == add(y, x) } } ᶄ೚ҙͷೖྗ஋
  16. 4XJGU$IFDLͰͷ଍͠ࢉͷੑ࣭ςετ 27 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    test_add_property() { // x + y == y + x property("଍͠ࢉ͸݁߹๏ଇΛຬͨ͢") <- forAll { (x: UInt, y: UInt) in return add(x, y) == add(y, x) } } ᶅશͯʹର͠
  17. 4XJGU$IFDLͰͷ଍͠ࢉͷੑ࣭ςετ 28 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    test_add_property() { // x + y == y + x property("଍͠ࢉ͸݁߹๏ଇΛຬͨ͢") <- forAll { (x: UInt, y: UInt) in return add(x, y) == add(y, x) } } ᶆ͜ͷ͕ࣜ੒Γཱͭ
  18. 4XJGU$IFDLͰͷ଍͠ࢉͷੑ࣭ςετ 29 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    test_add_property() { // x + y == y + x property("଍͠ࢉ͸݁߹๏ଇΛຬͨ͢") <- forAll { (x: UInt, y: UInt) in return add(x, y) == add(y, x) } } ᶃੑ࣭ͷએݴ ᶄ೚ҙͷೖྗ஋ ᶅશͯʹର͠ ᶆ͜ͷ͕ࣜ੒Γཱͭ
  19. Test Case '-[SwiftCheckSampleTests.SwiftCheckSampleTests test_add_property]' started. *** Passed 100 tests .

    *** Passed 100 tests . Test Case '-[SwiftCheckSampleTests.SwiftCheckSampleTests test_add_property]' passed (0.009 seconds). 4XJGU$IFDLͰͷςετ͕੒ޭ 31 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ίϯιʔϧ 1BTTFEUFTUT ݸ΋ͷϥϯμϜ஋Ͱςετ͕͞Ε͍ͯΔʂ
  20. ۩ମతʹબ͹Ε͍ͯͨ஋ 33 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Test

    Case '-[SwiftCheckSampleTests.SwiftCheckSampleTests test_add_property]' started. x: 0, y: 0 x: 1, y: 1 x: 0, y: 2 x: 3, y: 3 x: 0, y: 0 x: 1, y: 1 x: 0, y: 6 x: 4, y: 1 … x: 26, y: 19 x: 34, y: 51 x: 40, y: 18 x: 10, y: 13 x: 49, y: 22 x: 9, y: 14 x: 31, y: 65 x: 45, y: 15 x: 30, y: 32 x: 46, y: 54 x: 65, y: 34 x: 57, y: 41 … x: 58, y: 17 x: 67, y: 17 x: 41, y: 93 x: 21, y: 17 *** Passed 100 tests ϥϯμϜ͚ͩΕͲɺ খ͞Ίͷ஋͔Βςετ͞Ε͍ͯΔ
  21. *** Failed! Proposition: x + 1 + 1 == x

    + 2 Falsifiable (after 3 tests and 2 shrinks): 1 *** Passed 2 tests 4XJGU$IFDLͰͷςετ͕੒ޭ 35 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ίϯιʔϧ ஋͕ʮʯͷέʔεͰɺ ςετ͕ύε͠ͳ͔ͬͨ͜ͱ͕ใࠂ͞Εͨ
  22. 9$5"TTFSU&RVBMͰݕূ 37 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ͔֬ʹςετ͕ࣦഊͨ͠ʂ

    func add(_ x: UInt, _ y: UInt) -> UInt { return x * y } ݪҼ͸ֻ͚ࢉʹͳ͍ͬͯͨҝ
  23. 38 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. • 1SPQFSUZCBTFEUFTUJOHͱ͸ʁ

    • 4XJGU$IFDLͱ͸ʁ • ۩ମྫͰݟΔ • ྫ ଍͠ࢉ • ྫ ഑ྻͷ൓స • ༻ޠ • ࣮ફతͳϢʔεέʔε • ·ͱΊ
  24. func test_reversed() { property("഑ྻͷ൓సͷ൓స͸ݩͷ഑ྻͱಉ͡") <- forAll { (xs: ArrayOf<Int>) in

    let ys = xs.getArray return ys.reversed().reversed() == ys } } 4XJGU$IFDLͰ഑ྻͷ൓సͷςετ 43 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. YT<5> ͱදݱͰ͖ͳ͍ͷ͸4XJGUͷ੍ݶɻ ୅ΘΓʹ"SSBZ0G5ͱ͍͏ϥούʔΛࢦఆ͠ɺ HFU"SSBZͰத਎ΛऔΓग़͠ɻ "SSBZ0G*OU
  25. ͜͜·Ͱͷ·ͱΊ 45 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    1SPQFSUZCBTFEUFTUJOH • ςετͱͯ͠ੑ࣭ʢQSPQFSUZʣΛఆٛ • '8͕܁Γฦ͠ϥϯμϜ஋ͰςετΛ࣮ߦ • 4XJGU$IFDL • 9$5FTUͱ૊Έ߹Θͤͯ࢖͑Δ • ࣦഊͨ͠৔߹ɺͦͷ஋Λใࠂͯ͘͠ΕΔ • ͦͷ஋͸Ͱ͖Δ͚ͩখ͍͞஋͕બ͹Ε͍ͯΔ
  26. 46 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. • 1SPQFSUZCBTFEUFTUJOHͱ͸ʁ

    • 4XJGU$IFDLͱ͸ʁ • ۩ମྫͰݟΔ • ྫ ଍͠ࢉ • ྫ ഑ྻͷ൓స • ༻ޠ • ࣮ફతͳϢʔεέʔε • ·ͱΊ
  27. Arbitrary 49 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ʮ೚ҙͷʯͱ͍ͬͨҙຯ • 4XJGU$IFDLͰ͸ϓϩτίϧͱͯ͠ఆٛ • ಛఆͷܕͷϥϯμϜ஋Λੜ੒͢Δ໾ׂ • 4XJGUඪ४ͷܕʹ͸σϑΥϧτ࣮૷͕ఏڙ͞ΕΔ • ͜Εʹ४ڌ͢Δ͜ͱͰϥϯμϜ஋͕ੜ੒Ͱ͖ΔΑ͏ʹ public protocol Arbitrary { public static var arbitrary: SwiftCheck.Gen<Self> { get } public static func shrink(_: Self) -> [Self] }
  28. Shrinking 51 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ʮऩॖ͢Δʯͱ͍ͬͨҙຯ • ಉ͘͡"SCJUSBSZϓϩτίϧʹఆٛʢPQUJPOBMʣ • ΑΓখ͞ͳ஋ʹ͢Δ໾ׂ • ͜ΕʹΑΓࣦഊͨ͠ςετσʔλʹ͍ͭͯɺ
 ΑΓখ͞ͳࣦഊέʔεΛબग़͢Δ࢓૊Έ Int.shrink(10) // => [0, 1, 2, 5] String.shrink(“app") // => ["p", "pp", ... ,"apa", "apb"]
  29. Shrinking 52 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ʢࣦഊʣ
 ˣTISJOL • ʢࣦഊʣ
 ˣTISJOL • ʢࣦഊʣ⾣ɹ͜ΕΛʢ࠷খͷʣࣦഊྫͱͯ͠ใࠂ
 ˣTISJOL • ʢ੒ޭʣ
  30. 53 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. • 1SPQFSUZCBTFEUFTUJOHͱ͸ʁ

    • 4XJGU$IFDLͱ͸ʁ • ۩ମྫͰݟΔ • ྫ ଍͠ࢉ • ྫ ഑ྻͷ൓స • ༻ޠ • ࣮ફతͳϢʔεέʔε • ·ͱΊ
  31. Property-based testing ͕༗ޮͳέʔε 55 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. • ᶃ&ODPEF%FDPEF • ᶄ஗͘໌֬ͳΞϧΰϦζϜWTߴ଎ͳΞϧΰϦζϜ • ᶅϥϯμϜੑʹج͍ͮͨΞϧΰϦζϜ
  32. Encode / Decode ͷϢχοτςετ 57 Copyright (C) DeNA Co.,Ltd. All

    Rights Reserved. • ΘΓͱେม • ϓϩύςΟ͕ଟ͍ͱॻ͘ͷେม • ಉ͡ೖྗ஋Λ࢖͏ͱೖΕସ͑Λݕग़Ͱ͖ͳ͍ • ςετΛॻ͘࿑ྗʹݟ߹͍ͬͯΔ͔ʁ • ϦεΫ͕ߴ͍ • Ұݟਖ਼͘͠ಈ͍͍ͯΔΑ͏ʹΈ͑Δ • ͚ΕͲɺҰ෦ͷ߲໨͚͚͍ͩܽͯͨΓ
  33. Encode / Decode ͷੑ࣭ 58 Copyright (C) DeNA Co.,Ltd. All

    Rights Reserved. • &ODPEF%FDPEFͨ͠΋ͷ͸ݩͱಉ͡ • EFDPEF FODPEF PCK PCK
  34. Dogߏ଄ମ 59 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. public

    struct Dog: Equatable { let name: String let age: Int func encode() -> [String: String] { return [ "name": name, "age": "\(age)", ] } static func decode(_ encoded: [String: String]) -> Dog? { guard let name = encoded["name"], let age = (encoded["age"].flatMap{ Int($0) }) else { return nil } return Dog(name: name, age: age) } } public func == (a: Dog, b: Dog) -> Bool { return a.name == b.name && a.age == b.age }
  35. Dog Λ Arbiratyϓϩτίϧʹ४ڌͤ͞Δ 60 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. extension Dog: Arbitrary { public static var arbitrary: SwiftCheck.Gen<Dog> { return Gen<(String, Int)> .zip(String.arbitrary, Int.arbitrary) .map(Dog.init) } } ࠓճ͸TISJOLͷ࣮૷͸ׂѪ ʢͳͯ͘΋ಈ͖͸͢Δʣ
  36. SwiftCheckͰͷςετίʔυ 61 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    testDogEncodeDecode() { property(“DogΛencodeͯ͠decodeͨ͠΋ͷ͸ɺݩͱಉ͡") <- forAll { (dog: Dog) in guard let decoded = Dog.decode(dog.encode()) else { return false } return dog == decoded } } "SCJUSBSZʹ४ڌͨ͠ͷͰɺ ϥϯμϜ஋͕ੜ੒Ͱ͖ΔΑ͏ʹͳͬͨ
  37. ༷ʑͳσʔλͰςετ͞Ε͍ͯΔ 62 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Dog(name:

    "", age: 0) Dog(name: "O", age: 1) Dog(name: "d", age: 1) Dog(name: "ÇÆØ", age: 3) Dog(name: "!\\-", age: -4) Dog(name: "0S=ä", age: 3) Dog(name: "¡¨sóø", age: 1) Dog(name: "Ü+_<M", age: 4) Dog(name: "fín«ÄqÙv", age: -5) Dog(name: "ÁZõXü:¼¢", age: -4) Dog(name: "Ͼâñ. øýí", age: -9) Dog(name: "ùÝofNÁ&S", age: 9) Dog(name: " aÞäÈyÚ&Á", age: -5) Dog(name: "_¯¼Ì6<ÙRçv", age: 3) Dog(name: "êð©[ý#ùTó}°Õ|É", age: 7) Dog(name: "KVGH<ø«zE7\'", age: 12)
  38. ஗͘໌֬ͳΞϧΰϦζϜ vs ߴ଎ͳΞϧΰϦζϜ 64 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. • ΞϧΰϦζϜ • ໌֬ͳॻ͖ํΛ͢Δͱʢ͍͍ͩͨʣ஗͍ • ߴ଎ʹ͢Δͱʢ͍͍ͩͨʣίʔυ͕ෳࡶʹͳΔ • ςετͷ೉͠͞ • +BWBͷ4%,ʹؚ·ΕΔೋ෼୳ࡧ͸ɺ
 ೥ؒ΋όάʹؾ͔ͮΕͳ͔ͬͨ
  39. ஗͘໌֬ͳΞϧΰϦζϜ vs ߴ଎ͳΞϧΰϦζϜ 65 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. • ੑ࣭Λߟ͑Δ • ೖྗ஋͕ಉ͡Ͱ͋Ε͹ɺ྆ऀͷ݁Ռ͸ৗʹಉ͡
  40. ֊৐ΛٻΊΔίʔυ 66 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. //

    ֊৐Λ࠶ؼͰٻΊΔ func fact(_ n: Int) -> Int { if n == 1 { return 1 } return n * fact(n - 1) } // ֊৐ΛϧʔϓͰٻΊΔ func factFast(_ n: Int) -> Int { var r = n var i = n - 1 while i > 1 { r *= i i = i - 1 } return r } ࠶ؼ൛͸͍͕ٙͳ͍͘Β͍ʹ໌֬ɻ͚ΕͲίʔϧ ελοΫͷ෼ɺύϑΥʔϚϯε͸ѱ͍
  41. SwiftCheckͰͷςετίʔυ 67 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. func

    test_fact() { // 1ʙ20ͷ஋ΛબͿʢେ͖͗͢ΔͱΤϥʔʹͳΔͨΊʣ let gen: Gen<Int> = Gen<Int>.choose((1, 20)) property("fact()ͱfactFast()͸ৗʹಉ݁͡ՌΛฦ͢͜ͱ") <- forAll(gen) { (n: Int) in return fact(n) == factFast(n) } } ໌֬ͳΞϧΰϦζϜͷ݁ՌͱҰக͍ͯ͠Ε͹ɺߴ ଎ͳΞϧΰϦζϜ΋ਖ਼͘͠ػೳ͍ͯ͠Δͱߟ͑Β ΕΔ DIPPTFͰ஋ͷൣғΛ੍ݶ
  42. ϥϯμϜੑʹج͍ͮͨΞϧΰϦζϜ 69 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    έʔε • μϯδϣϯϚοϓͷੜ੒ • μΠεϩʔϧ • ੑ࣭Λߟ͑Δ • Ϛοϓ͸ඞͣΰʔϧʹͭͳ͕͍ͬͯΔ͜ͱ • Ϛοϓʹ౸ୡͰ͖ͳ͍෦԰͕ͳ͍͜ͱ • े෼ʹۉ౳ͳϥϯμϜੑ͕ಘΒΕΔ͜ͱ
  43. ·ͱΊ 71 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    1SPQFSUZCBTFEUFTUJOH • ੑ࣭ʢQSPQFSUZʣʹண໨ͨ͠Ϣχοτςετख๏ • ଟ਺ͳϥϯμϜ஋Ͱςετ͞ΕΔ • 4XJGU$IFDLͰ9$5FTUͱ૊Έ߹Θͤͯ࢖͑Δ • ࢖͍Ͳ͜Ζ • ޻෉࣍ୈͰ͍Ζ͍Ζ͋Γͦ͏ • &YBNQMFCBTFEUFTUJOHͱ஥ྑ͘