単体テストのハジメ

 単体テストのハジメ

iOS Test Night #15 で発表した資料です

830d824769dd94553ab4e9955765f967?s=128

yokoya-s000

July 26, 2017
Tweet

Transcript

  1. 12.

    ҉໧తͳೖग़ྗͷςετྫ ˙ 6TFS%FGBVMUT͔Βऔಘͨ͠஋Λ࢖͏ؔ਺Λςετ͢Δ৔߹ class HogeTests: XCTestCase { func testHoge() {

    UserDefaults.resetStandardUserDefaults() let testValue = 10 UserDefaults.standard.set(testValue, forKey: "hoge") // something to do... UserDefaults.standard.removeObject(forKey: "hoge") } }
  2. 13.

    class HogeTests: XCTestCase { func testHoge() { UserDefaults.resetStandardUserDefaults() let testValue

    = 10 UserDefaults.standard.set(testValue, forKey: "hoge") // something to do... UserDefaults.standard.removeObject(forKey: "hoge") } } ҉໧తͳೖग़ྗͷςετྫ ˙ 6TFS%FGBVMUT͔Βऔಘͨ͠஋Λ࢖͏ؔ਺Λςετ͢Δ৔߹ ຊମίʔυɺ΋͘͠͸ଞͷςετ͔Β มߋ͞Ε͍ͯΔՄೳੑ͕͋ΔͷͰɺ 6TFS%FGBVMUTΛॳظঢ়ଶʹ͔ͯ͠Βελʔτ
  3. 14.

    class HogeTests: XCTestCase { func testHoge() { UserDefaults.resetStandardUserDefaults() let testValue

    = 10 UserDefaults.standard.set(testValue, forKey: "hoge") // something to do... UserDefaults.standard.removeObject(forKey: "hoge") } } ҉໧తͳೖग़ྗͷςετྫ ˙ 6TFS%FGBVMUT͔Βऔಘͨ͠஋Λ࢖͏ؔ਺Λςετ͢Δ৔߹ ςετΛߦ͏ͨΊʹʮࣄલʹೖ͍ͬͯͯཉ͍͠஋ʯΛ 6TFS%FGBVMUTʹ௚઀ॻ͖ࠐΉ
  4. 15.

    class HogeTests: XCTestCase { func testHoge() { UserDefaults.resetStandardUserDefaults() let testValue

    = 10 UserDefaults.standard.set(testValue, forKey: "hoge") // something to do... UserDefaults.standard.removeObject(forKey: "hoge") } } ҉໧తͳೖग़ྗͷςετྫ ˙ 6TFS%FGBVMUT͔Βऔಘͨ͠஋Λ࢖͏ؔ਺Λςετ͢Δ৔߹ ຊମίʔυɺ΋͘͠͸ଞͷςετ΁
 ӨڹΛ༩͑ͳ͍ͨΊʹɺ 6TFS%FGBVMUTʹՃ͑ͨมߋΛऔΓফ͢
  5. 20.

    ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int }
  6. 21.

    ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } େҬม਺͔Βऔಘ͍ͯ͠Δ
  7. 22.

    ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } େҬม਺͔Βऔಘ͍ͯ͠Δ ςετ࣌͸ِ෺ʹࠩ͠ସ͍͑ͨ
  8. 23.

    ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } େҬม਺͔Βऔಘ͍ͯ͠Δ ςετ࣌͸ِ෺ʹࠩ͠ସ͍͑ͨ ελϒΛ࢖͍͍ͨ
  9. 24.

    ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } ςετ࣌͸ِ෺ʹࠩ͠ସ͍͑ͨ ελϒΛ࢖͍͍ͨ ελϒΛ࢖͑Δঢ়ଶʹ͢Δʂ େҬม਺͔Βऔಘ͍ͯ͠Δ
  10. 29.

    ελϒΛ࢖͑Δঢ়ଶʹ͢Δ class Input { private let repository: ReadableRepositoryContract func multiplication(int:

    Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } } ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  11. 30.

    ελϒΛ࢖͑Δঢ়ଶʹ͢Δ class Input { private let repository: ReadableRepositoryContract init (repository:

    ReadableRepositoryContract) { self.repository = repository } func multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } } ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  12. 31.

    ελϒΛ࢖͑Δঢ়ଶʹ͢Δ class Input { private let repository: ReadableRepositoryContract init (repository:

    ReadableRepositoryContract) { self.repository = repository } func multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } } ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  13. 32.

    class Input { private let repository: ReadableRepositoryContract init (repository: ReadableRepositoryContract)

    { self.repository = repository } func multiplication(int: Int) -> Int { let base = self.repository.read() return base * int } } ελϒΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  14. 33.

    class Input { private let repository: ReadableRepositoryContract init (repository: ReadableRepositoryContract)

    { self.repository = repository } func multiplication(int: Int) -> Int { let base = self.repository.read() return base * int } } ελϒΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋
  15. 34.

    class Input { private let repository: ReadableRepositoryContract init (repository: ReadableRepositoryContract)

    { self.repository = repository } func multiplication(int: Int) -> Int { let base = self.repository.read() return base * int } } ελϒΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ ˙ ཁ݅3FQPTJUPSZ͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋
  16. 37.

    ελϒΛ࢖ͬͯςετΛॻ͘ class ReadableRepositoryStub: ReadableRepositoryContract { private let base: Int init(base:

    Int) { self.base = base } func read() -> Int { return self.base } } 1SPUPDPMʹ४ڌͨ͠ελϒΛ࡞੒͢Δ
  17. 38.

    class ReadableRepositoryStub: ReadableRepositoryContract { private let base: Int init(base: Int)

    { self.base = base } func read() -> Int { return self.base } } ελϒΛ࢖ͬͯςετΛॻ͘ 1SPUPDPMʹ४ڌͨ͠ελϒΛ࡞੒͢Δ ʮِ෺ͷৼΔ෣͍ʯΛߦͳ͍ͬͯΔՕॴ
  18. 39.

    class InputTests: XCTestCase { func testMultiplication() { let base =

    5 let int = 2 let expected = 10 } } ˙ ςετέʔε ɾظ଴͕ฦͬͯ͘Δ ελϒΛ࢖ͬͯςετΛॻ͘ ɾঢ়گCBTF JOUͷ࣌
  19. 40.

    class InputTests: XCTestCase { func testMultiplication() { let base =

    5 let int = 2 let expected = 10 let repositoryStub = ReadableRepositoryStub(base: base) let input = Input(repository: repositoryStub) } } ɾঢ়گCBTF JOUͷ࣌ ˙ ςετέʔε ɾظ଴͕ฦͬͯ͘Δ ελϒΛ࢖ͬͯςετΛॻ͘ ελϒΛࠩ͠ࠐΉ
  20. 41.

    class InputTests: XCTestCase { func testMultiplication() { let base =

    5 let int = 2 let expected = 10 let repositoryStub = ReadableRepositoryStub(base: base) let input = Input(repository: repositoryStub) let actual = input.multiplication(int: int) XCTAssertEqual(actual, expected) } } ɾঢ়گJOU CBTFͷ࣌ ˙ ςετέʔε ɾظ଴͕ฦͬͯ͘Δ ελϒΛ࢖ͬͯςετΛॻ͘ தͰελϒ͕࢖ΘΕ͍ͯΔ
  21. 42.
  22. 46.

    class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ
  23. 47.

    class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ ςετ࣌͸ผͷ৔ॴʹه࿥͍ͨ͠
  24. 48.

    class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ ςετ࣌͸ผͷ৔ॴʹه࿥͍ͨ͠ εύΠΛ࢖͍͍ͨ
  25. 49.

    class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ ςετ࣌͸ผͷ৔ॴʹه࿥͍ͨ͠ εύΠΛ࢖͍͍ͨ εύΠΛ࢖͑Δঢ়ଶʹ͢Δʂ
  26. 54.

    class Output { private let repository: WritableRepositoryContract func write(int: Int)

    { UserDefaults.standard.set(int, forKey: "write") } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  27. 55.

    class Output { private let repository: WritableRepositoryContract init(repository: WritableRepositoryContract) {

    self.repository = repository } func write(int: Int) { UserDefaults.standard.set(int, forKey: "write") } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  28. 56.

    class Output { private let repository: WritableRepositoryContract init(repository: WritableRepositoryContract) {

    self.repository = repository } func write(int: Int) { UserDefaults.standard.set(int, forKey: "write") } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  29. 57.

    class Output { private let repository: WritableRepositoryContract init(repository: WritableRepositoryContract) {

    self.repository = repository } func write(int: Int) { self.repository.write(int: int) } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  30. 58.

    class Output { private let repository: WritableRepositoryContract init(repository: WritableRepositoryContract) {

    self.repository = repository } func write(int: Int) { self.repository.write(int: int) } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ
  31. 59.

    class Output { private let repository: WritableRepositoryContract init(repository: WritableRepositoryContract) {

    self.repository = repository } func write(int: Int) { self.repository.write(int: int) } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ3FQPTJUPSZʹ౉͢
  32. 62.

    εύΠΛ࢖ͬͯςετΛॻ͘ 1SPUPDPMʹ४ڌͨ͠εύΠΛ࡞੒͢Δ class WritableRepositorySpy: WritableRepositoryContract { /// ϝιου͕ݺͼग़͞ΕͨࡍͷҾ਺ྻɻ private(set) var

    callArguments: [Int] = [] func write(int: Int) { self.record(int) } private func record(_ args: Int) { self.callArguments += [args] } }
  33. 63.

    class WritableRepositorySpy: WritableRepositoryContract { /// ϝιου͕ݺͼग़͞ΕͨࡍͷҾ਺ྻɻ private(set) var callArguments: [Int]

    = [] func write(int: Int) { self.record(int) } private func record(_ args: Int) { self.callArguments += [args] } } εύΠΛ࢖ͬͯςετΛॻ͘ ϓϩτίϧ४ڌ 1SPUPDPMʹ४ڌͨ͠εύΠΛ࡞੒͢Δ
  34. 64.

    class WritableRepositorySpy: WritableRepositoryContract { /// ϝιου͕ݺͼग़͞ΕͨࡍͷҾ਺ྻɻ private(set) var callArguments: [Int]

    = [] func write(int: Int) { self.record(int) } private func record(_ args: Int) { self.callArguments += [args] } } εύΠΛ࢖ͬͯςετΛॻ͘ ݺͼग़͠Λه࿥͢Δ 1SPUPDPMʹ४ڌͨ͠εύΠΛ࡞੒͢Δ
  35. 66.

    εύΠΛ࢖ͬͯςετΛॻ͘ ɾঢ়گJOUͷ࣌ ˙ ςετέʔε ɾظ଴6TFS%FGBVMUT΁lz͕อଘ͞ΕΔ class OutputTests: XCTestCase { func

    testWrite() { let int = 2 let spy = WritableRepositorySpy() let output = Output(repository: spy)
 } } εύΠΛࠩ͠ࠐΉ
  36. 67.

    εύΠΛ࢖ͬͯςετΛॻ͘ ɾঢ়گJOUͷ࣌ ˙ ςετέʔε ɾظ଴6TFS%FGBVMUT΁lz͕อଘ͞ΕΔ class OutputTests: XCTestCase { func

    testWrite() { let int = 2 let spy = WritableRepositorySpy() let output = Output(repository: spy)
 output.write(int: int) XCTAssertEqual(int, spy.callArguments.first!) } } தͰεύΠ͕࢖ΘΕ͍ͯΔ
  37. 68.

    εύΠΛ࢖ͬͯςετΛॻ͘ ɾঢ়گJOUͷ࣌ ˙ ςετέʔε ɾظ଴6TFS%FGBVMUT΁lz͕อଘ͞ΕΔ class OutputTests: XCTestCase { func

    testWrite() { let int = 2 let spy = WritableRepositorySpy() let output = Output(repository: spy)
 output.write(int: int) XCTAssertEqual(int, spy.callArguments.first!) } } εύΠʹه࿥͞Εͨ஋Λ֬ೝ͢Δ
  38. 69.