Swift testing with XCTest and Cuckoo
Sorry but reading that constant and variable names can contain almost any character, including Unicode characters I could not resist π ...
- Create
HelloMessage
class in HelloMessage.swift:
class HelloMessage {
var π: String {
get {
return "Hello World!"
}
}
}
- Same way create
HelloConsole
class in HelloConsole.swift:
class HelloConsole {
func print(π: String) {
Swift.print(π)
}
}
- Create
HelloApp
class in HelloApp.swift:
class HelloApp {
let message: HelloMessage
let console: HelloConsole
init(message: HelloMessage, console: HelloConsole) {
self.message = message
self.console = console
}
func printHello() {
console.print(π: message.π)
}
}
- Create main class in Main.swift that wraps it all together:
@main
public struct Main {
public static func main() {
let message = HelloMessage()
let console = HelloConsole()
let app = HelloApp(message: message, console: console)
app.printHello()
}
}
Following XCTest and Cuckoo guides ...
- Mock generation
Mocks have to be generated statically, you can follow these instructions or alternatively:
- Build generator (only once, XCode command line tools required):
git clone git@github.com:Brightify/Cuckoo.git /tmp/Cuckoo
/tmp/Cuckoo/build_generator
- Generate mocks (as many times as needed):
/tmp/Cuckoo/Generator/bin/cuckoo_generator generate \
--testable Hello \
--output Tests/Mocks.swift \
Sources/HelloMessage.swift \
Sources/HelloConsole.swift
You can also integrate mocks generation in the build, before compile phase.
- Test
HelloMessage
in HelloMessageTest.swift:
final class HelloMessageTest: XCTestCase {
func testHelloMessageShouldReturnHelloWorld() throws {
let message = HelloMessage()
XCTAssertEqual(message.π, "Hello World!")
}
}
- Test
HelloApp
in HelloAppTest.swift:
final class HelloAppTest: XCTestCase {
func testHelloAppShouldDisplayHelloMessage() throws {
let messageText = "Hello Test!"
// 2.1 Create a mock of HelloMessage
let message = MockHelloMessage()
// 2.2 Return "Hello Test!" whenever π getter is called
stub(message) { stub in
when(stub.π.get).thenReturn(messageText)
}
// 2.2 Create a mock of HelloConsole
let console = MockHelloConsole()
// 2.3 Do nothing whenever print is called
stub(console) { stub in
when(stub.print(π: anyString())).thenDoNothing()
}
// 2.4 Create a HelloApp, the one we want to test, passing the mocks
let app = HelloApp(message: message, console: console)
// 2.5 Execute the method we want to test
app.printHello()
// 2.6 Verify HelloConsole mock print() method
// has been called once with "Hello Test!"
verify(console).print(π: messageText)
}
}
- Test output should look like:
Test Suite 'All tests' started at 2023-12-12 16:48:21.225
Test Suite 'debug.xctest' started at 2023-12-12 16:48:21.227
Test Suite 'HelloAppTest' started at 2023-12-12 16:48:21.227
Test Case 'HelloAppTest.testHelloAppShouldDisplayHelloMessage' started at 2023-12-12 16:48:21.227
Test Case 'HelloAppTest.testHelloAppShouldDisplayHelloMessage' passed (0.003 seconds)
Test Suite 'HelloAppTest' passed at 2023-12-12 16:48:21.230
Executed 1 test, with 0 failures (0 unexpected) in 0.003 (0.003) seconds
Test Suite 'HelloMessageTest' started at 2023-12-12 16:48:21.230
Test Case 'HelloMessageTest.testHelloMessageShouldReturnHelloWorld' started at 2023-12-12 16:48:21.231
Test Case 'HelloMessageTest.testHelloMessageShouldReturnHelloWorld' passed (0.001 seconds)
Test Suite 'HelloMessageTest' passed at 2023-12-12 16:48:21.232
Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'debug.xctest' passed at 2023-12-12 16:48:21.232
Executed 2 tests, with 0 failures (0 unexpected) in 0.004 (0.004) seconds
Test Suite 'All tests' passed at 2023-12-12 16:48:21.232
Executed 2 tests, with 0 failures (0 unexpected) in 0.004 (0.004) seconds
Run this project using π³ docker
- Execute
./docker-run.sh
- Once inside the container:
- Test with
swift test
- Run with
swift run
- Build with
swift build -c release
- Run executable with
$(swift build --show-bin-path -c release)/Hello
- Test with
- Install Swift
- If you need to build Cuckoo mock generator, install XCode command line tools
- Test with
swift test
- Run with
swift run
- Build with
swift build -c release
- Run executable with
$(swift build --show-bin-path -c release)/Hello
- Create project using
swift package init --name Hello --type executable
- Customize Package.swift:
- Add
Cuckoo
package as a dependency - Add
HelloTests
testTarget withHello
andCuckoo
dependencies
- Add