Update: unless you really want to decorate your test logs, there's a much shorter way to get the tests to run in Playgrounds. Using the same class Tests as further below, this is all it takes:

Tests.defaultTestSuite().run()

Playgrounds are already nice to swiftly test out an idea or practice your katas. But you can take them up a notch by equiping them with a test runner.

First import XCTest and prepare an NSObject subclass delegate that implements a function from XCTestObservation that will let you know of any failed tests:

class TestObserver: NSObject, XCTestObservation {
  func testCase(_ testCase: XCTestCase, didFailWithDescription description: String, inFile filePath: String?, atLine lineNumber: UInt) {
    print("❌Test failed on line \(lineNumber): \(testCase.name!), \(description)")
  }
}
XCTestObservationCenter.shared().addTestObserver(TestObserver())

Then add a TestRunner and run the Tests:

struct TestRunner {
  static func run(_ tests: XCTestCase.Type) {
    let testSuite = tests.defaultTestSuite()
    testSuite.run()
    let run = testSuite.testRun!
    run.totalFailureCount == 0
      ? print("✅ All \(run.executionCount) tests passed")
      : print("\(run.executionCount)/\(run.totalFailureCount) tests failed")
  }
}
TestRunner.run(Tests.self)

That's it! Now you can not only join the ranks of programmers who can fizz-buzz, but also quickly and thoroughly test it1:

class Tests: XCTestCase {
  func testFizzBuzz() {
    for i in 1...100 {
      switch (i%3, i%5) {
      case (0,0):
        XCTAssert(fizzBuzz(i) == "FizzBuzz")
      case (0,_):
        XCTAssert(fizzBuzz(i) == "Fizz")
      case (_,0):
        XCTAssert(fizzBuzz(i) == "Buzz")
      case (_,_):
        XCTAssert(fizzBuzz(i) == "\(i)")
      }
    }
  }
}

Inspiration taken from Stuart Sharpe, with my own improvements on top.


  1. Any test in the Tests class should be prefixed with test