Use when writing tests for Swift StateTree - ensures proper Swift Testing framework usage
Guidelines for writing tests using Swift Testing framework (Swift 6's new testing framework, not XCTest).
Announce at start: "I'm using the swift-testing-guidelines skill to write proper tests."
Important: Swift StateTree uses Swift Testing (Swift 6's new testing framework), NOT XCTest.
@Test attribute instead of func test...()#expect() instead of XCTAssert*Issue.record() for test failuresTests are organized by module:
*Tests.swiftStateTreeTests.swift)Basic test:
import Testing
@Test("Description of what is being tested")
func testBasicFunctionality() {
let result = functionUnderTest()
#expect(result == expectedValue)
}
Test with setup/teardown:
@Test("Test with setup and assertions")
func testWithSetup() {
// Arrange
let input = createTestInput()
// Act
let result = functionUnderTest(input)
// Assert
#expect(result.isValid)
#expect(result.value == expectedValue)
}
Basic usage:
@Test
func testSomething() {
// ...
}
With description:
@Test("Verifies that state sync works correctly")
func testStateSync() {
// ...
}
With arguments:
@Test(arguments: [1, 2, 3, 4, 5])
func testWithNumber(_ number: Int) {
#expect(number > 0)
}
Basic expectation:
#expect(condition)
Equality:
#expect(actual == expected)
Inequality:
#expect(actual != expected)
Comparison:
#expect(value > threshold)
#expect(value < limit)
Optional unwrapping:
#expect(optional != nil)
let value = #require(optional) // Unwraps or fails test
Record test failure:
if condition {
Issue.record("Condition not met: \(reason)")
}
Structure tests with clear sections:
@Test("Test state update propagation")
func testStateUpdate() {
// Arrange
let initialState = createInitialState()
let syncEngine = SyncEngine()
// Act
let update = try syncEngine.generateDiff(
for: playerID,
from: initialState
)
// Assert
#expect(update.patches.count > 0)
#expect(update.type == .diff)
}
struct StateTreeTests {
@Test("Initial state is empty")
func testInitialState() {
// ...
}
@Test("State update creates patches")
func testStateUpdate() {
// ...
}
@Test("State sync includes all fields")
func testStateSync() {
// ...
}
}
Good:
@Test("State sync includes broadcast fields for all players")
func testBroadcastFieldsIncluded() {
// ...
}
Bad:
@Test
func test1() {
// ...
}
swift test must passswift test
swift test --filter StateTreeTests.testGetSyncFields
swift test list
swift test -c release
Good:
#expect(result.count == expectedCount, "Expected \(expectedCount) items, got \(result.count)")
Bad:
#expect(result.count == expectedCount)
@Test("Async operation completes")
func testAsyncOperation() async throws {
let result = try await asyncFunction()
#expect(result != nil)
}
@Test("Function throws on invalid input")
func testThrowsOnInvalidInput() {
#expect(throws: SomeError.self) {
try functionThatThrows(invalidInput)
}
}
@Test("Collection contains expected items")
func testCollection() {
let items = createItems()
#expect(items.count == 3)
#expect(items.contains(expectedItem))
}
Location: Examples/Demo/WebClient
Command:
cd Examples/Demo/WebClient && npm test
Framework: Vitest (for Vue component and business logic tests)
Location: Tools/CLI
Basic E2E (DemoServer):
cd Tools/CLI && ./test-e2e-ci.sh # Recommended: auto server + all encodings
cd Tools/CLI && npm test # Requires DemoServer running
Matchmaking E2E (Control Plane + GameServer):
cd Tools/CLI && npm run test:e2e:game:matchmaking:full # Direct, no LB
cd Tools/CLI && npm run test:e2e:game:matchmaking:nginx # With nginx LB (requires Docker)
See: SwiftStateTree/run-e2e-tests skill for details
// ❌ DON'T DO THIS
import XCTest
class StateTreeTests: XCTestCase {
func testSomething() {
XCTAssertEqual(actual, expected)
}
}
// ❌ DON'T DO THIS
var sharedState = State()
@Test
func test1() {
sharedState.value = 1 // Affects other tests!
}
@Test
func test2() {
#expect(sharedState.value == 0) // May fail due to test1
}
// ❌ DON'T DO THIS
@Test
func testInternalMethod() {
let result = object.internalMethod() // Testing private API
#expect(result == expected)
}
When reviewing test code:
@Test attribute (not XCTest)#expect() for assertions*Tests.swift