Slide 1

Slide 1 text

~Better Specs ʹֶͿ~ Swiftʹ͓͚Δຊ౰ʹ
 RSpecϥΠΫͳςετͷॻ͖ํ iOS Test Night #9 - 2प೥ - 2018/12/10 @rockname

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

ΈͯͶͰ͸νʔϜશମͰ
 ςετΛॻ͘จԽ͕
 ࠜ෇͍͍ͯΔ

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

BDDͰςετΛॻ͘ͳΒ
 ಡΈ΍͍͢ςετΛॻ͖͍ͨ…ʂ

Slide 7

Slide 7 text

Better Specs

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

RSpecʹӨڹ͞ΕͨQuickͰ΋ Better Specs ʹͳΒͬͯ
 ՄಡੑΛ্͛Δͧ

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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) } } }

Slide 12

Slide 12 text

·ͣ͸Կ΋ߟ͑ͣʹͱΓ͋͑ͣ
 ςετΛॻ͍ͯΈΔ ✍

Slide 13

Slide 13 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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")) } } } }

Slide 14

Slide 14 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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")) } } } } ςετର৅ͷϝιου

Slide 15

Slide 15 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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")) } } } } ظ଴͞ΕΔϝιουͷ;Δ·͍

Slide 16

Slide 16 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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”

Slide 17

Slide 17 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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”

Slide 18

Slide 18 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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”

Slide 19

Slide 19 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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”

Slide 20

Slide 20 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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")) } } } } ͦΕҎ֎ͷ࣌ -> ༩͑ΒΕͨ਺ࣈ

Slide 21

Slide 21 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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")) } } } }

Slide 22

Slide 22 text

ͳʹ΋ߟ͑ͣʹॻ͍ͨςετ 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")) } } } } ύοͱݟͯ΋ϝιουͷৼΔ෣͍͕ ཧղ͠ʹ͍͘

Slide 23

Slide 23 text

Better Specs 1. ୯Ұ৚݅ςετ
 2. ContextΛ࢖͏
 3. SubjectΛ࢖͏

Slide 24

Slide 24 text

Better Specs 1. ୯Ұ৚݅ςετ
 2. ContextΛ࢖͏
 3. SubjectΛ࢖͏

Slide 25

Slide 25 text

#FUUFS4QFDT

Slide 26

Slide 26 text

#FUUFS4QFDT

Slide 27

Slide 27 text

#FUUFS4QFDT

Slide 28

Slide 28 text

୯Ұ৚݅ςετ 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")) } ɾ ɾ ɾ

Slide 29

Slide 29 text

୯Ұ৚݅ςετ 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”

Slide 30

Slide 30 text

୯Ұ৚݅ςετ 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”

Slide 31

Slide 31 text

୯Ұ৚݅ςετ 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”

Slide 32

Slide 32 text

Better Specs 1. ୯Ұ৚݅ςετ
 2. ContextΛ࢖͏
 3. SubjectΛ࢖͏

Slide 33

Slide 33 text

#FUUFS4QFDT

Slide 34

Slide 34 text

#FUUFS4QFDT

Slide 35

Slide 35 text

#FUUFS4QFDT

Slide 36

Slide 36 text

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")) } } ɾ ɾ ɾ

Slide 37

Slide 37 text

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”

Slide 38

Slide 38 text

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”

Slide 39

Slide 39 text

Better Specs 1. ୯Ұ৚݅ςετ
 2. ContextΛ࢖͏
 3. SubjectΛ࢖͏

Slide 40

Slide 40 text

#FUUFS4QFDT

Slide 41

Slide 41 text

#FUUFS4QFDT

Slide 42

Slide 42 text

#FUUFS4QFDT

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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")) } } ɾ ɾ ɾ

Slide 45

Slide 45 text

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ΛܭࢉܕϓϩύςΟͱͯ͠એݴ

Slide 46

Slide 46 text

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ม਺ʹ୅ೖ

Slide 47

Slide 47 text

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ͷΈ౉͢

Slide 48

Slide 48 text

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")) } } ɾ ɾ ɾ

Slide 49

Slide 49 text

Ͳ͏มΘͬͨͷ

Slide 50

Slide 50 text

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")) } } } }

Slide 51

Slide 51 text

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")) } } ɾ ɾ ɾ

Slide 52

Slide 52 text

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)

Slide 53

Slide 53 text

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)

Slide 54

Slide 54 text

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)

Slide 55

Slide 55 text

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)

Slide 56

Slide 56 text

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)

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Thank you!!!