Slide 1

Slide 1 text

Sleipnir BDD style testing for Swift

Slide 2

Slide 2 text

Who we are • Mobile team at railsware.com • Open source fans railsware.github.io/

Slide 3

Slide 3 text

Outline • What is BDD • Testing in Swift - XCTest vs BDD style • What Sleipnir is • How to use it • Questions

Slide 4

Slide 4 text

BDD

Slide 5

Slide 5 text

BDD Behavior Driven Development

Slide 6

Slide 6 text

BDD Behavior Driven Development • BDD specifies that tests of any unit of software should be specified in terms of the desired behaviour of the unit. (from Wiki) ! • BDD is all about specifications

Slide 7

Slide 7 text

BDD describe("Calculator") { ! describe("#add") { ! it("returns the sum of its arguments") { expect(Calculator().add(1, 2)).to(equal(3)) } } }

Slide 8

Slide 8 text

Testing in Swift

Slide 9

Slide 9 text

Testing in Swift - XCTest class BookTest : XCTestCase { func testPersonHasName() { let person = Person(name: "John Doe”) ! XCTAssertNotNil(person.name, "name should not be nil") XCTAssertEqual(person.name, "John Doe", "incorrect name") } }

Slide 10

Slide 10 text

Testing in Swift - XCTest class BookTest : XCTestCase { func testPersonHasName() { let person = Person(name: "John Doe”) ! XCTAssertNotNil(person.name, "name should not be nil") XCTAssertEqual(person.name, "John Doe", "incorrect name") } } Does not specify behavior of the `Person` class

Slide 11

Slide 11 text

Testing in Swift - BDD class PersonSpec : SleipnirSpec { var personSpec = describe("Person") { let person = Person(name: "John Doe") context("name") { it("should not be nil") { expect(person.name).toNot(beNil()) } it("should be correct") { expect(person.name).to(equal("John Doe")) } } } }

Slide 12

Slide 12 text

Testing in Swift - BDD Test code is a specification of a class: • Person name should not be nil • Person name should be correct

Slide 13

Slide 13 text

Introducing Sleipnir https://github.com/railsware/Sleipnir

Slide 14

Slide 14 text

What Sleipnir is Mythological steed of Odin, Norse God

Slide 15

Slide 15 text

What Sleipnir is BDD-style framework for Swift

Slide 16

Slide 16 text

What Sleipnir is class HorseSpec : SleipnirSpec { var spec = describe("Horse") { context("usual") { it("is not awesome") { let usualHorse = UsualHorse() expect(usualHorse.legsCount).to(equal(4)) usualHorse.isAwesome.should.beFalse() } } context("Sleipnir") { it("is awesome") { let sleipnirHorse = Sleipnir() expect(sleipnirHorse.legsCount).to(equal(8)) sleipnirHorse.isAwesome.should.beTrue() } } } }

Slide 17

Slide 17 text

Core principles • Not using XCTest • Pure Swift BDD testing framework • Command line output • Seeded random tests invocation

Slide 18

Slide 18 text

How to use it

Slide 19

Slide 19 text

Running specs 1. Create a test target in Xcode 2. Invoke Runner.run() method in main.swift 3. Run test target

Slide 20

Slide 20 text

Running specs Running With Random Seed: 7197 ! ...F...... ! ! FAILURE Some spec should pass: /Path/To/Your/Specs/SomeSpec.swift:27 Expected <1> to equal <3> ! ! Finished in 0.0102 seconds ! 10 examples, 1 failures

Slide 21

Slide 21 text

Setup/Teardown blocks • beforeEach { } • afterEach { } • beforeAll { } • afterAll { }

Slide 22

Slide 22 text

Setup/Teardown blocks let someSpec = describe("Some spec") { var someArray: [Int]? ! beforeEach { someArray = [1, 2, 3] } afterEach { someArray = nil } it("should pass") { expect(someArray).toNot(beNil()) expect(someArray).to(contain(3)) } }

Slide 23

Slide 23 text

Focused specs Focus means “Run only focused stuff” Useful in a project with a lot of specs

Slide 24

Slide 24 text

Focused specs describe("Some spec") { fit("focused") { // WILL RUN } it("not focused") { // WILL NOT RUN } }

Slide 25

Slide 25 text

Focused specs fdescribe("focused group") { // ... } ! fcontext("focused group") { // ... } fit("focused example") { // ... }

Slide 26

Slide 26 text

Pending specs Pending means “Don’t run this stuff” Useful to denote an example that does not pass yet

Slide 27

Slide 27 text

Pending specs xdescribe("Pending group") { it("will not run") { expect(false).to(beTrue()) } it("is pending", PENDING) } Running With Random Seed: 2428 ! ...P....... ! PENDING Pending group is pending ! ! Finished in 0.0062 seconds ! 11 examples, 0 failures, 1 pending

Slide 28

Slide 28 text

Shared example groups Useful for extracting common specs Allow to run same specs in different context

Slide 29

Slide 29 text

Shared example groups sharedExamplesFor("some awesome stuff") { (sharedContext : SharedContext) in var stuff: Stuff? beforeEach { stuff = sharedContext()["stuff"] as Stuff } it("should be awesome") { expect(stuff.awesome).to(beTrue()) } }

Slide 30

Slide 30 text

Matchers • equal • beNil • beFalse/beTrue • beGreaterThan/beLessThan expect(3).to(equal(3)) expect(3).toNot(beNil()) expect(true).to(beTrue()) expect(3).to(beGreaterThan(1))

Slide 31

Slide 31 text

Matchers on collections/strings • contain • beginWith/endWith • beEmpty expect([1,2,3]).to(contain(1,2)) expect("foobar").to(beginWith("foo")) expect([1,2,3]).toNot(beEmpty())

Slide 32

Slide 32 text

Questions? https://github.com/railsware/Sleipnir