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

単体テストのハジメ

 単体テストのハジメ

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

Avatar for yokoya-s000

yokoya-s000

July 26, 2017
Tweet

More Decks by yokoya-s000

Other Decks in Technology

Transcript

  1. ҉໧తͳೖग़ྗͷςετྫ ˙ 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. 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. 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. 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. ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int }
  6. ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } େҬม਺͔Βऔಘ͍ͯ͠Δ
  7. ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } େҬม਺͔Βऔಘ͍ͯ͠Δ ςετ࣌͸ِ෺ʹࠩ͠ସ͍͑ͨ
  8. ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

    multiplication(int: Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } େҬม਺͔Βऔಘ͍ͯ͠Δ ςετ࣌͸ِ෺ʹࠩ͠ସ͍͑ͨ ελϒΛ࢖͍͍ͨ
  9. ҉໧తೖྗͷςετΛ͢ΔͨΊʹελϒΛ࢖͏ ˙ ཁ݅6TFS%FGBVMUT͔Βऔಘͨ͠஋ *OU  Ҿ਺໭Γ஋ class Input { func

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

    Int) -> Int { let base = UserDefaults.standard.integer(forKey: “base") return base * int } } ᶅ҉໧తೖྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ
  11. ελϒΛ࢖͑Δঢ়ଶʹ͢Δ 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. ελϒΛ࢖͑Δঢ়ଶʹ͢Δ 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. 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. 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. 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. ελϒΛ࢖ͬͯςετΛॻ͘ class ReadableRepositoryStub: ReadableRepositoryContract { private let base: Int init(base:

    Int) { self.base = base } func read() -> Int { return self.base } } 1SPUPDPMʹ४ڌͨ͠ελϒΛ࡞੒͢Δ
  17. class ReadableRepositoryStub: ReadableRepositoryContract { private let base: Int init(base: Int)

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

    5 let int = 2 let expected = 10 } } ˙ ςετέʔε ɾظ଴͕ฦͬͯ͘Δ ελϒΛ࢖ͬͯςετΛॻ͘ ɾঢ়گCBTF JOUͷ࣌
  19. 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. 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. class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ
  22. class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ ςετ࣌͸ผͷ৔ॴʹه࿥͍ͨ͠
  23. class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ ςετ࣌͸ผͷ৔ॴʹه࿥͍ͨ͠ εύΠΛ࢖͍͍ͨ
  24. class Output { func write(int: Int) { UserDefaults.standard.set(int, forKey: "write")

    } } ҉໧తग़ྗͷςετΛ͢ΔͨΊʹεύΠΛ࢖͏ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ େҬม਺΁ه࿥͍ͯ͠Δ ςετ࣌͸ผͷ৔ॴʹه࿥͍ͨ͠ εύΠΛ࢖͍͍ͨ εύΠΛ࢖͑Δঢ়ଶʹ͢Δʂ
  25. class Output { private let repository: WritableRepositoryContract func write(int: Int)

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

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

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

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

    self.repository = repository } func write(int: Int) { self.repository.write(int: int) } } εύΠΛ࢖͑Δঢ়ଶʹ͢Δ ᶅ҉໧తग़ྗͷՕॴͰ͸1SPUPDPMΛར༻͢ΔΑ͏ʹมߋ͢Δ ˙ ཁ݅Ҿ਺Ͱड͚औͬͨ஋Λ6TFS%FGBVMUTʹอଘ͢Δ
  30. 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ʹ౉͢
  31. εύΠΛ࢖ͬͯςετΛॻ͘ 1SPUPDPMʹ४ڌͨ͠εύΠΛ࡞੒͢Δ class WritableRepositorySpy: WritableRepositoryContract { /// ϝιου͕ݺͼग़͞ΕͨࡍͷҾ਺ྻɻ private(set) var

    callArguments: [Int] = [] func write(int: Int) { self.record(int) } private func record(_ args: Int) { self.callArguments += [args] } }
  32. class WritableRepositorySpy: WritableRepositoryContract { /// ϝιου͕ݺͼग़͞ΕͨࡍͷҾ਺ྻɻ private(set) var callArguments: [Int]

    = [] func write(int: Int) { self.record(int) } private func record(_ args: Int) { self.callArguments += [args] } } εύΠΛ࢖ͬͯςετΛॻ͘ ϓϩτίϧ४ڌ 1SPUPDPMʹ४ڌͨ͠εύΠΛ࡞੒͢Δ
  33. 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. εύΠΛ࢖ͬͯςετΛॻ͘ ɾঢ়گJOUͷ࣌ ˙ ςετέʔε ɾظ଴6TFS%FGBVMUT΁lz͕อଘ͞ΕΔ class OutputTests: XCTestCase { func

    testWrite() { let int = 2 let spy = WritableRepositorySpy() let output = Output(repository: spy)
 } } εύΠΛࠩ͠ࠐΉ
  35. εύΠΛ࢖ͬͯςετΛॻ͘ ɾঢ়گ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!) } } தͰεύΠ͕࢖ΘΕ͍ͯΔ
  36. εύΠΛ࢖ͬͯςετΛॻ͘ ɾঢ়گ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!) } } εύΠʹه࿥͞Εͨ஋Λ֬ೝ͢Δ