DEV Community

Cover image for Tests Everywhere - Swift
Roger Viñas Alcon
Roger Viñas Alcon

Posted on

Tests Everywhere - Swift

GitHub logo rogervinas / tests-everywhere

🤠 Tests, Tests Everywhere!

Swift testing this simple Hello World with XCTest and Cuckoo

Show me the code

Implementation

Sorry but reading that constant and variable names can contain almost any character, including Unicode characters I could not resist 😅 ...

1) Create HelloMessage class in HelloMessage.swift:

class HelloMessage {
  var 👋: String {
    get {
      return "Hello World!"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2) Same way create HelloConsole class in HelloConsole.swift:

class HelloConsole {
  func print(👋: String) {
    Swift.print(👋)
  }
}
Enter fullscreen mode Exit fullscreen mode

3) 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.👋)
  }
}
Enter fullscreen mode Exit fullscreen mode

4) 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()
  }
}
Enter fullscreen mode Exit fullscreen mode

Test

Following XCTest and Cuckoo guides ...

1) Mock generation

Mocks have to be generated statically, you can follow these instructions or alternatively:

git clone git@github.com:Brightify/Cuckoo.git /tmp/Cuckoo
/tmp/Cuckoo/build_generator
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

You can also integrate mocks generation in the build, before compile phase.

2) Test HelloMessage in HelloMessageTest.swift:

final class HelloMessageTest: XCTestCase {
  func testHelloMessageShouldReturnHelloWorld() throws {
    let message = HelloMessage()
    XCTAssertEqual(message.👋, "Hello World!")
  }
}
Enter fullscreen mode Exit fullscreen mode

3) 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)
  }
}
Enter fullscreen mode Exit fullscreen mode

4) 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
Enter fullscreen mode Exit fullscreen mode

Happy Testing! 💙

Top comments (0)