StubKit provides a set of functions that speed up a process of creation of Swift stubs/mocks. It's goal is to require minimal amount of developer's work in mock creation while leveraging Swift's type system type integrity for safety without meta programming nor any code-generation.
Stubs created using StubKit provide :
- a full introspection of function calls
- passed arguments
- control to declarativly specify its return value(s)
- verify mock's expectations (synchronous and asynchronous)
// Implementation target: Sample protocol
protocol Database {
func addUser(name: String) -> Int
func addAccount(givenName: String, lastName: String) throws -> Int
}
// Test target: mock creation
class DatabaseStub: Database {
lazy var addUserAction = stub(of: addUser)
func addUser(name: String) -> Int {
return addUserAction(name)
}
lazy var addAccountAction = stub(of: addAccount)
func addAccount(givenName: String, lastName: String) throws -> Int {
return try addAccountAction((givenName, lastName))
}
}
// Test target, testcase Arange
let databaseStub = DatabaseStub()
Calls and arguments verification:
let addUserSpy = spyCalls(of: &databaseStub.addUserAction)
let addAccountSpy = spyCalls(of: &databaseStub.addAccountAction)
databaseStub.addUser(name: "User1") // return 0 (Int's default)
try databaseStub.addAccount(givenName: "John", lastName: "Appleseed") // returns 0
XCTAssertEqual(addUserSpy, ["User1"])
XCTAssertEqual(addAccountSpy.count, 1)
XCTAssertEqual(addAccountSpy[0]?.0, "John")
XCTAssertEqual(addAccountSpy[0]?.1, "Appleseed")
Control return value on fly
setupStubSequence(of: &databaseStub.addUserAction).returns(11)
setupStubSequence(of: &databaseStub.addAccountAction)
.returnsOnce(1)
.throws(DatabseError.ioError)
databaseStub.addUser(name: "User2") // return 11
try databaseStub.addAccount(givenName: "John", lastName: "Appleseed") // returns 1
try databaseStub.addAccount(givenName: "John", lastName: "Appleseed") // throws `DatabseError.ioError`
Synchronous mock verification
let user3Squence = setupStubSequence(of: &databaseStub.addUserAction)
.when("User3")
.expect(.once)
let user3TwiceSquence = setupStubSequence(of: &databaseStub.addUserAction)
.when("User3")
.expect(.times(2))
let appleseedSquence = setupStubSequence(of: &databaseStub.addAccountAction)
.whenSecond("Appleseed")
.expect(.atLeastOnce)
.returns(99)
databaseStub.addUser(name: "User3") // return 0
try databaseStub.addAccount(givenName: "John", lastName: "Appleseed") // returns 99
try databaseStub.addAccount(givenName: "Tim", lastName: "Appleseed") // returns 99
SKTVerify(user3Squence) // ✅
SKTVerify(user3TwiceSquence) // 🛑
SKTVerify(appleseedSquence) // ✅
XCTAssert(appleseedSquence.verify()) // ✅ - equivalent to SKTVerify(appleseedSquence)
Asynchronous mock verification
setupStubSequence(of: &databaseStub.addUserAction)
.when("User3")
.expect(.once)
.attach(expectation(description: "User3 added once"))
setupStubSequence(of: &databaseStub.addAccountAction)
.whenFirst("John")
.expect(.once)
.attach(expectation(description: "John added once"))
.returns(100)
DispatchQueue.global(qos: .background).async {
databaseStub.addUser(name: "User3") // return 0
try? databaseStub.addAccount(givenName: "John", lastName: "Appleseed") // returns 100
try? databaseStub.addAccount(givenName: "Tim", lastName: "Appleseed") // returns 99
}
waitForExpectations(timeout: 0.1) //✅
For API documentation, see external document: API Documentation
Swift | StubKit |
---|---|
4.2 , 5.0 |
~> 0.1 |
StubKit does not introduce any changes between Swift 4.2 and Swift 5.0
Swift Package Manager
To depend on the StubKit package, you need to declare your dependency in your Package.swift
:
.package(url: "https://github.com/polac24/StubKit.git", from: "0.1.0")
and to your application/library target, add "StubKit" to your dependencies.
Carthage
Add the following line to your Cartfile
:
github "polac24/StubKit" ~> 0.1
For detailed instruction to integrate carthage dependency, see Carthage
CocoaPods
StubKit is available through CocoaPods. To install
it, simply add StubKit
dependency for your testing target, like:
target 'StubKitExampleTests' do
inherit! :search_paths
pod 'StubKit'
end
Bartosz Polaczyk, [email protected]
StubKit is available under the MIT license. See the LICENSE file for more info.