Moocher

A set of "rspec-like" test matchers that "mooch" off of XCTest.
Adding Moocher to your project
CocoaPods
CocoaPods is the recommended way to add Moocher to your project.
- Add
Moocherto your Podfilepod 'Moocher'. - Install the pod(s) by running
pod install. - Add
Moocherto your files withimport Moocher.
Swift Package Manager
Swift Package Manager can be used to add Moocher the to your project:
- Add
.package(url: "https://github.com/rbaumbach/Moocher", from: "0.4.0") - Follow intructions to add the
Moocherpackage to your project.
Note: Since Moocher requires the library XCTest, when you add Moocher to your project, be sure that it's added to your unit testing target.
Clone from Github
- Clone repository from github and copy files directly, or add it as a git submodule.
- Add all files from
Sources/Moocherdirectory to your project.
Usage
Moocher matchers are inspired by RSpec:
expect(AnswerToUltimateQuestion.value).to.equal(42)Equivalence and Identity
equal
This matcher works for types that conform to Equatable, but also works for types that conform to FloatingPoint as well.
expect(99).to.equal(99)
expect(99).toNot.equal(100)
expect(9.9).to.equal(9.9, within: 0.1)
expect(9.9).toNot.equal(10.9, within: 0.1)Types
beInstanceOf
class Dog { }
let chihuahua = Dog()
let pancho = chihuahua
let miniPinscher = Dog()
expect(chihuahua).to.beInstanceOf(pancho)
expect(chihuahua).toNot.beInstanceOf(miniPinscher)beKindOf
class Dog { }
struct Fish { }
let dog = Dog()
expect(dog).to.beKindOf(Dog.self)
expect(dog).toNot.beKindOf(Fish.self)conformTo
protocol Wolf { }
class Dog: Wolf { }
protocol Goat { }
let dog = Dog()
expect(dog).to.conformTo(Wolf.self)
expect(dog).toNot.conformTo(Goat.self)Comparisons
beLessThan
expect(9).to.beLessThan(10)
expect(9).toNot.beLessThan(8)beLessThanOrEqualTo
expect(9).to.beLessThanOrEqualTo(9)
expect(11).toNot.beLessThanOrEqualTo(10)beGreaterThan
expect(9).to.beGreaterThan(8)
expect(7).toNot.beGreaterThan(8)beGreaterThanOrEqualTo
expect(9).to.beGreaterThanOrEqualTo(8)
expect(7).toNot.beGreaterThanOrEqualTo(8)Truthiness
beTruthy
expect(true).to.beTruthy()
expect(false).toNot.beTruthy()beFalsy
expect(false).to.beFalsy()
expect(true).toNot.beFalsy()beNil
var number: Int?
expect(number).to.beNil()
number = 99
expect(number).toNot.beNil()Error Throwing
throwError
The throwError matcher can be used in 4 different ways:
throwError(block:)
expect({ try functionThatThrowsAnError() })
.to.throwError()
expect({ try functionThatDoesNotThrowAnError() })
.toNot.throwError()throwError(block:errorHandler:)
expect({ try functionThatThrowsAnError() })
.to.throwError { error in
// Do something with error
}throwError(block:specificError:)
expect({ try functionThatThrowsABurritoError() })
.to.throwError(specificError: BurritoError.beansMissing))
expect({ try functionThatThrowsABurritoError() })
.toNot.throwError(specificError: TacoError.salsaMissing))throwError(block:errorType:)
expect({ try functionThatThrowsABurritoError() })
.to.throwError(errorType: BurritoError.self))
expect({ try functionThatThrowsABurritoError() })
.toNot.throwError(errorType: TacoError.self))Collection
beEmpty
This matcher works for types that conform to Collection.
let emptyArray: [Int] = []
expect(emptyArray).to.beEmpty()
expect([1, 2, 3]).toNot.beEmpty()This matcher also works for Strings as well.
expect("").to.beEmpty()
expect("Taco").toNot.beEmpty()startWith
expect(["a", "b", "c"]).to.startWith("a")
expect([2, 4, 8]).toNot.startWith(1)endWith
expect(["a", "b", "c"]).to.endWith("c")
expect([2, 4, 8]).toNot.endWith(7)haveSizeOf
expect(["taco", "burrito"]).to.haveSizeOf(2)
expect([2, 4, 8]).toNot.haveSizeOf(7)Sequence
contain
This matcher works for types that conform to Sequence.
expect(["uno", "dos", "tres"]).to.contain("tres")
expect("Billy Goat").toNot.contain("$")This matcher also works for finding a substring within a String.
expect("Corey and Trevor").to.contain("and")
expect("Richard LaFleur").toNot.contain("Smart")Compound matchers
Some of the matchers allow for compounding assertions:
expect([1, 2, 3]).to.contain(1).and.startWith(1).and.endWith(3)
expect([1, 2, 3]]).toNot.haveSizeOf(4).and.contain(7)The following matchers can be used compoundly:
startWithendWithcontainhaveSizeOfhaveMinValueOfhaveMaxValueOf
Moocher Polling
This repo also contains an additional library for polling values when writing integration tests that have to "wait" for assertions.
This can be added to your project:
CocoaPods
- Add
MoocherPollingto your Podfilepod 'Moocher/Polling'. - Install the pod(s) by running
pod install. - Add
MoocherPollingto your files withimport MoocherPolling.
Swift Package Manager
- Add
MoocherPollingto your target:Build Phases->Link Binary With Libraries. - Add
MoocherPollingto your files withimport MoocherPolling.
HangOn
HangOn is a function that allows block input that will wait for an assertion given a specific timeframe.
hangOn(for: .seconds(10)) { complete in
var number = 100
DispatchQueue.global(qos: .background).async { [weak self] in
sleep(3)
number = 99
DispatchQueue.main.async {
expect(number).to.equal(99)
complete()
}
}
}toSomeday and toNever
Values can be constantly polled using familiar expect syntax using toSomeday and toNever.
var dogArray = ["Chihuhahua", "Miniature Pinscher", "Border Collie"]
DispatchQueue.global(qos: .background).async {
sleep(3)
dogArray.append("German Shepard")
}
expect(dogArray).toSomeday.contain("German Shepard")var dogArray = ["Chihuhahua", "Miniature Pinscher", "Border Collie"]
DispatchQueue.global(qos: .background).async {
sleep(3)
dogArray.append("German Shepard")
}
expect(dogArray).toNever.contain("Poodle")The expect clause will block tests from running until either a timeout has been hit, or the assertion you expect is true. The default timeout is 5 seconds. This can be set by providing a timeout value.
The interval in which the polling is done on the value being asserted has a default interval of 100 milliseconds. This can be set by providing a pollingInterval value.
expect(dogArray, timeout: .seconds(10), pollingInterval: .miliseconds(500)).toSomeday.contain("German Shepard")The following matchers can be used for toSomeday and toNever:
beNilequalcontain