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

Swiftにおける本当にRSpecライクなテストの書き方 / RSpec-like Test in Swift

rockname
December 10, 2018

Swiftにおける本当にRSpecライクなテストの書き方 / RSpec-like Test in Swift

rockname

December 10, 2018
Tweet

More Decks by rockname

Other Decks in Programming

Transcript

  1. ~Better Specs ʹֶͿ~
    Swiftʹ͓͚Δຊ౰ʹ

    RSpecϥΠΫͳςετͷॻ͖ํ
    iOS Test Night #9 - 2प೥ -
    2018/12/10
    @rockname

    View Slide

  2. @rockname
    גࣜձࣾϛΫγΟ / ΈͯͶࣄۀ෦
    ΞϓϦ։ൃG 18৽ଔ
    iOS(Swift, objc) > Android(Kotlin, Java) == Rails(ruby)
    ˎॻ͘ྔͷॱ൪

    View Slide

  3. ΈͯͶͰ͸νʔϜશମͰ

    ςετΛॻ͘จԽ͕

    ࠜ෇͍͍ͯΔ

    View Slide

  4. ςετ͕ͳ͔ͬͨΒbotʹἤΒΕΔ

    View Slide

  5. iOSͷςετ؀ڥ
    • ςετϑϨʔϜϫʔΫͱͯ͠ Quick/Nimble Λ࠾༻
    • RSpecʹΠϯεύΠΞ͞ΕͨBDD Framework
    • ΈͯͶ͸ServerͷςετΛRSpecͰॻ͍͍ͯΔͷͰ׳Ε͍ͯΔਓ͕ؒ
    ଟ͍
    • Mock͸…
    • ಛʹϥΠϒϥϦ͸࢖͍ͬͯͳ͍ (Φεεϝ͕͋Ε͹ڭ͍͑ͯͩ͘͞)
    • Mock ObjectΛςετ͝ͱʹఆ͍ٛͯ͠Δ

    View Slide

  6. BDDͰςετΛॻ͘ͳΒ

    ಡΈ΍͍͢ςετΛॻ͖͍ͨ…ʂ

    View Slide

  7. Better Specs

    View Slide

  8. Better Specs ͱ͸ʁ
    • RSpecʹ͓͚Δྑ͍ςετͷ࡞ΓํΛूΊͨΨΠυϥΠϯ
    • GitHubͰopenʹ؅ཧ͞Ε͍ͯΔ
    • ॻ͖ํʹٙ໰͕͋Ε͹issue্Ͱٞ࿦͢Δ͜ͱ͕Ͱ͖Δ
    • RSpecͷॻ͖ํʹ໎ͬͨΒྑ͘ݟΔ

    View Slide

  9. RSpecʹӨڹ͞ΕͨQuickͰ΋
    Better Specs ʹͳΒͬͯ

    ՄಡੑΛ্͛Δͧ

    View Slide

  10. FizzBuzzؔ਺ͷςετΛॻ͘
    • Ҿ਺ʹIntΛऔΓɺ
    • 3ͷഒ਺ͷ࣌ -> “Fizz”
    • 5ͷഒ਺ͷ࣌ -> “Buzz”
    • 3ͱ5ͷެഒ਺ͷ࣌ -> “FizzBuzz”
    • 0ҎԼͷ࣌ -> “out of range”
    • ͦΕҎ֎ͷ࣌ -> ༩͑ΒΕͨ਺ࣈΛͦͷ··ฦ͢

    View Slide

  11. FizzBuzzؔ਺
    enum FizzBuzz {
    static func fizzBuzz(_ number: Int) -> String {
    guard number > 0 else { return "out of range” }
    switch number {
    case let n where n % 15 == 0: return "FizzBuzz"
    case let n where n % 5 == 0: return "Buzz"
    case let n where n % 3 == 0: return "Fizz"
    default: return String(number)
    }
    }
    }

    View Slide

  12. ·ͣ͸Կ΋ߟ͑ͣʹͱΓ͋͑ͣ

    ςετΛॻ͍ͯΈΔ ✍

    View Slide

  13. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }

    View Slide

  14. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    ςετର৅ͷϝιου

    View Slide

  15. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    ظ଴͞ΕΔϝιουͷ;Δ·͍

    View Slide

  16. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    3ͷഒ਺ͷ࣌ -> “Fizz”

    View Slide

  17. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    5ͷഒ਺ͷ࣌ -> “Buzz”

    View Slide

  18. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    3ͱ5ͷެഒ਺ͷ࣌ -> “FizzBuzz”

    View Slide

  19. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    0ҎԼͷ࣌ -> ”out of range”

    View Slide

  20. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    ͦΕҎ֎ͷ࣌ -> ༩͑ΒΕͨ਺ࣈ

    View Slide

  21. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }

    View Slide

  22. ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }
    ύοͱݟͯ΋ϝιουͷৼΔ෣͍͕
    ཧղ͠ʹ͍͘

    View Slide

  23. Better Specs
    1. ୯Ұ৚݅ςετ

    2. ContextΛ࢖͏

    3. SubjectΛ࢖͏

    View Slide

  24. Better Specs
    1. ୯Ұ৚݅ςετ

    2. ContextΛ࢖͏

    3. SubjectΛ࢖͏

    View Slide

  25. #FUUFS4QFDT

    View Slide

  26. #FUUFS4QFDT

    View Slide

  27. #FUUFS4QFDT

    View Slide

  28. ୯Ұ৚݅ςετ
    describe("#fizzBuzz") {
    it("should return Fizz when given multiples of 3") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    it("should return Buzz when given multiples of 5") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    it("should return FizzBuzz
    when given multiples of both 3 and 5") {
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    }
    ɾ
    ɾ
    ɾ

    View Slide

  29. ୯Ұ৚݅ςετ
    describe("#fizzBuzz") {
    it("should return Fizz when given multiples of 3") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    it("should return Buzz when given multiples of 5") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    it("should return FizzBuzz
    when given multiples of both 3 and 5") {
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    }
    ɾ
    ɾ
    ɾ
    3ͷഒ਺ͷ࣌ -> “Fizz”

    View Slide

  30. ୯Ұ৚݅ςετ
    describe("#fizzBuzz") {
    it("should return Fizz when given multiples of 3") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    it("should return Buzz when given multiples of 5") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    it("should return FizzBuzz
    when given multiples of both 3 and 5") {
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    }
    ɾ
    ɾ
    ɾ
    5ͷഒ਺ͷ࣌ -> “Buzz”

    View Slide

  31. ୯Ұ৚݅ςετ
    describe("#fizzBuzz") {
    it("should return Fizz when given multiples of 3") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    it("should return Buzz when given multiples of 5") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    it("should return FizzBuzz
    when given multiples of both 3 and 5") {
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    }
    ɾ
    ɾ
    ɾ
    3ͱ5ͷެഒ਺ͷ࣌ -> “FizzBuzz”

    View Slide

  32. Better Specs
    1. ୯Ұ৚݅ςετ

    2. ContextΛ࢖͏

    3. SubjectΛ࢖͏

    View Slide

  33. #FUUFS4QFDT

    View Slide

  34. #FUUFS4QFDT

    View Slide

  35. #FUUFS4QFDT

    View Slide

  36. ContextΛ࢖͏
    describe("#fizzBuzz") {
    context("when given multiples of 3") {
    it("should return Fizz") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    }
    context("when given multiples of 5") {
    it("should return Buzz") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    }
    ɾ
    ɾ
    ɾ

    View Slide

  37. ContextΛ࢖͏
    describe("#fizzBuzz") {
    context("when given multiples of 3") {
    it("should return Fizz") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    }
    context("when given multiples of 5") {
    it("should return Buzz") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    }
    ɾ
    ɾ
    ɾ
    3ͷഒ਺ͷ࣌ -> “Fizz”

    View Slide

  38. ContextΛ࢖͏
    describe("#fizzBuzz") {
    context("when given multiples of 3") {
    it("should return Fizz") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    }
    }
    context("when given multiples of 5") {
    it("should return Buzz") {
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    }
    }
    ɾ
    ɾ
    ɾ
    5ͷഒ਺ͷ࣌ -> “Buzz”

    View Slide

  39. Better Specs
    1. ୯Ұ৚݅ςετ

    2. ContextΛ࢖͏

    3. SubjectΛ࢖͏

    View Slide

  40. #FUUFS4QFDT

    View Slide

  41. #FUUFS4QFDT

    View Slide

  42. #FUUFS4QFDT

    View Slide

  43. #FUUFS4QFDT
    subject = ςετର৅ͷओମ

    View Slide

  44. SubjectΛ࢖͏
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ

    View Slide

  45. SubjectΛ࢖͏
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    Ҿ਺Λม਺ͱͯ͠ఆٛ
    subjectΛܭࢉܕϓϩύςΟͱͯ͠એݴ

    View Slide

  46. SubjectΛ࢖͏
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    beforeEach ͰcontextʹԠͨ͡

    ஋Λnumberม਺ʹ୅ೖ

    View Slide

  47. SubjectΛ࢖͏
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    ɹexpectʹ͸subjectͷΈ౉͢

    View Slide

  48. SubjectΛ࢖͏
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ

    View Slide

  49. Ͳ͏มΘͬͨͷ

    View Slide

  50. Before
    class FizzBuzzSpec: QuickSpec {
    override func spec() {
    describe("#fizzBuzz") {
    it("should meet all FizzBuzz specifications") {
    expect(FizzBuzz.fizzBuzz(3)).to(equal("Fizz"))
    expect(FizzBuzz.fizzBuzz(5)).to(equal("Buzz"))
    expect(FizzBuzz.fizzBuzz(15)).to(equal("FizzBuzz"))
    expect(FizzBuzz.fizzBuzz(-1))
    .to(equal(“out of range"))
    expect(FizzBuzz.fizzBuzz(1)).to(equal("1"))
    }
    }
    }
    }

    View Slide

  51. After
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ

    View Slide

  52. After
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    Կ͕ (What)

    View Slide

  53. After
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    Կ͕ (What)
    ͍ͭ (When)

    View Slide

  54. After
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    ͍ͭ (When)
    Կ͕ (What)
    Ͳ͏ͳΔͷ͔ (How)

    View Slide

  55. After
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    ͍ͭ (When)
    Կ͕ (What)
    Ͳ͏ͳΔͷ͔ (How)

    View Slide

  56. After
    describe("#fizzBuzz") {
    var number: Int!
    var subject: String {
    return FizzBuzz.fizzBuzz(number)
    }
    context("when given multiples of 3") {
    beforeEach {
    number = 3
    }
    it("should return Fizz") {
    expect(subject).to(equal("Fizz"))
    }
    }
    ɾ
    ɾ
    ɾ
    ͍ͭ (When)
    Կ͕ (What)
    Ͳ͏ͳΔͷ͔ (How)

    View Slide

  57. ·ͱΊ
    • Quick͸RSpecʹΠϯεύΠΞ͞ΕͨBDD Framework
    • BetterSpecsʹͳΒͬͯॻ͘͜ͱͰɺͦͷϝιουͷ࢓༷͕ཧղ͠
    ΍͘͢ͳΔςετΛॻ͚Δ (Spec = Specification = ࢓༷ॻ)
    • ͨͩɺ޷͖ݏ͍͸ඞͣ͋ΔͷͰڧ੍͸ྑ͘ͳ͍ 

    (XCTestͰ΋What/When/HowΛҙࣝͨ͠ςετ͸ॻ͚Δ)

    View Slide

  58. Thank you!!!

    View Slide