StubKit
Overview:
Description
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)
Sample
// 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) //✅
Full API Documentation
For API documentation, see external document: API Documentation
Requirements
Swift | StubKit |
---|---|
4.2 , 5.0 |
~> 0.1 |
StubKit does not introduce any changes between Swift 4.2 and Swift 5.0
Installation
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
Author
Bartosz Polaczyk, [email protected]
License
StubKit is available under the MIT license. See the LICENSE file for more info.