tests-developer
Provides standard patterns for writing unit tests, mocks, and edge cases in Swift using XCTest or the Swift Testing framework.
Install
mkdir -p .claude/skills/tests-developer && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/6982" && unzip -o skill.zip -d .claude/skills/tests-developer && rm skill.zipInstalls to .claude/skills/tests-developer
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Smart router to testing patterns and practices. Use when writing unit tests, creating mocks, testing edge cases, or working with Swift Testing and XCTest frameworks.Key capabilities
- →Structure test suites using Swift Testing
- →Create mock helpers via extensions
- →Test edge cases for nil/empty values
- →Update existing test suite references
- →Enforce test-driven development practices
How it works
Provides structural guidance and boilerplate patterns for implementing tests using the Swift Testing framework and XCTest.
Inputs & outputs
When to use tests-developer
- →Write unit tests for new features
- →Create test mocks in extensions
- →Test edge cases like nil values or empty collections
- →Refactor existing test suites
About this skill
Tests Developer Skill
Smart router to testing patterns and practices. Writing unit tests, creating mocks, test organization.
When to Use This Skill
This skill activates when working with:
- Writing unit tests
- Creating test mocks
- Testing edge cases
- Test-driven development (TDD)
- Test refactoring and updates
- Swift Testing framework usage
- XCTest framework usage
Quick Reference
Critical Rules
- ✅ Use Swift Testing framework (
import Testing,@Test,@Suite) for NEW tests - ✅ Keep existing XCTest tests as-is (don't migrate unless necessary)
- ✅ Test edge cases: nil values, empty collections, boundary conditions
- ✅ Create mock helpers in test file extensions when needed
- ✅ Update tests when refactoring - always search and update references
- ❌ Never skip tests for data transformation or business logic
- ❌ Never use force unwrapping in tests - use proper assertions
Test File Naming
ProductionCode: SetContentViewDataBuilder.swift
Test File: SetContentViewDataBuilderTests.swift
Location: AnyTypeTests/[Category]/[TestFile].swift
Swift Testing Framework (Preferred for New Tests)
Basic Structure:
import Testing
import Foundation
@testable import Anytype
import Services
@Suite
struct MyFeatureTests {
private let sut: MyFeature // System Under Test
init() {
self.sut = MyFeature()
}
@Test func testSpecificBehavior() {
// Arrange
let input = "test"
// Act
let result = sut.process(input)
// Assert
#expect(result == "expected")
}
@Test func testEdgeCase_EmptyInput_ReturnsNil() {
let result = sut.process("")
#expect(result == nil)
}
}
Suite Options:
@Suite // Parallel execution (default)
@Suite(.serialized) // Sequential execution (for shared state)
Assertions:
#expect(value == expected) // Equality
#expect(value != unexpected) // Inequality
#expect(result != nil) // Not nil
#expect(array.isEmpty) // Boolean conditions
#expect(throws: SomeError.self) { // Error throwing
try throwingFunction()
}
XCTest Framework (Legacy Tests)
Basic Structure:
import XCTest
@testable import Anytype
final class MyFeatureTests: XCTestCase {
var sut: MyFeature!
override func setUpWithError() throws {
sut = MyFeature()
}
override func tearDownWithError() throws {
sut = nil
}
func testSpecificBehavior() {
// Arrange
let input = "test"
// Act
let result = sut.process(input)
// Assert
XCTAssertEqual(result, "expected")
}
}
Common Assertions:
XCTAssertEqual(actual, expected)
XCTAssertNotEqual(actual, unexpected)
XCTAssertNil(value)
XCTAssertNotNil(value)
XCTAssertTrue(condition)
XCTAssertFalse(condition)
XCTAssertThrowsError(try expression)
Test Organization Patterns
1. Edge Case Testing (Critical)
Always test these scenarios:
@Test func testEmptyInput() {
let result = sut.process([])
#expect(result.isEmpty)
}
@Test func testNilInput() {
let result = sut.process(nil)
#expect(result == nil)
}
@Test func testSingleItem() {
let result = sut.process([item])
#expect(result.count == 1)
}
@Test func testBoundaryCondition() {
let items = (0..<100).map { Item(id: "\($0)") }
let result = sut.process(items)
#expect(result.count <= 100)
}
@Test func testTruncation_LimitsToMax() {
let attachments = (0..<5).map { ObjectDetails.mock(id: "item\($0)") }
let result = sut.truncate(attachments, limit: 3)
#expect(result.count == 3)
#expect(result[0].id == "item0")
#expect(result[2].id == "item2")
}
2. Mock Helpers (In Test File)
Location: Create as extensions in the same test file
// At bottom of test file
extension ObjectDetails {
static func mock(id: String) -> ObjectDetails {
ObjectDetails(id: id, values: [:])
}
}
extension Participant {
static func mock(
id: String,
globalName: String = "",
icon: ObjectIcon? = nil
) -> Participant {
Participant(
id: id,
localName: "",
globalName: globalName,
icon: icon,
status: .active,
permission: .reader,
identity: "",
identityProfileLink: "",
spaceId: "",
type: ""
)
}
}
3. Dependency Injection in Tests
Using Factory Pattern:
@Suite(.serialized) // Required for DI setup
struct MyFeatureTests {
private let mockService: MyServiceMock
init() {
let mockService = MyServiceMock()
Container.shared.myService.register { mockService }
self.mockService = mockService
}
@Test func testWithMockedDependency() {
mockService.expectedResult = "test"
let sut = MyFeature()
let result = sut.doWork()
#expect(result == "test")
}
}
4. Testing Protocols (Make Methods Internal)
Problem: Private methods can't be tested
Solution: Use internal access and test via protocol
// Production code - SetContentViewDataBuilder.swift
final class SetContentViewDataBuilder: SetContentViewDataBuilderProtocol {
// ✅ Internal for testing (not private)
func buildChatPreview(
objectId: String,
spaceView: SpaceView?,
chatPreviewsDict: [String: ChatMessagePreview]
) -> MessagePreviewModel? {
// Implementation
}
}
// Test code
@Test func testBuildChatPreview_EmptyDict_ReturnsNil() {
let result = builder.buildChatPreview(
objectId: "test",
spaceView: nil,
chatPreviewsDict: [:]
)
#expect(result == nil)
}
5. Dictionary Conversion Testing
Performance validation:
@Test func testDictionaryConversion_EmptyArray() {
let items: [Item] = []
let dict = Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })
#expect(dict.isEmpty)
}
@Test func testDictionaryConversion_MultipleItems() {
let items = (0..<10).map { Item(id: "item\($0)") }
let dict = Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })
#expect(dict.count == 10)
for i in 0..<10 {
#expect(dict["item\(i)"] != nil)
}
}
@Test func testDictionaryLookup_O1Performance() {
let items = (0..<100).map { Item(id: "item\($0)") }
let dict = Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })
let result = dict["item50"]
#expect(result != nil)
#expect(result?.id == "item50")
}
6. Testing with Dates
@Test func testDateFormatting() {
let date = Date(timeIntervalSince1970: 1700000000)
let result = formatter.format(date)
#expect(result.isEmpty == false)
}
@Test func testDateComparison() {
let now = Date()
let future = now.addingTimeInterval(3600)
#expect(future > now)
}
7. Testing Protobuf Models
ChatState example:
@Test func testChatStateCounters() {
var chatState = ChatState()
var messagesState = ChatState.UnreadState()
messagesState.counter = 5
chatState.messages = messagesState
var mentionsState = ChatState.UnreadState()
mentionsState.counter = 2
chatState.mentions = mentionsState
#expect(chatState.messages.counter == 5)
#expect(chatState.mentions.counter == 2)
}
Mock Services Pattern
Preview Mocks (for SwiftUI Previews)
Location: Anytype/Sources/PreviewMocks/
Usage:
import SwiftUI
#Preview {
MockView {
// Configure mock state
SpaceViewsStorageMock.shared.workspaces = [...]
} content: {
MyView()
}
}
Test Mocks (for Unit Tests)
Location: AnyTypeTests/Mocks/ or in test file
Pattern:
@testable import Anytype
final class MyServiceMock: MyServiceProtocol {
var callCount = 0
var capturedInput: String?
var stubbedResult: Result?
func process(_ input: String) -> Result {
callCount += 1
capturedInput = input
return stubbedResult ?? .default
}
}
Testing Checklist
When writing tests, ensure:
- Test happy path (valid input, expected output)
- Test edge cases (nil, empty, boundary conditions)
- Test error conditions (invalid input, throwing functions)
- Test data transformations (truncation, filtering, mapping)
- Test performance assumptions (O(1) lookups, O(n) operations)
- Create mock helpers for complex types
- Use descriptive test names:
testFeature_Condition_ExpectedBehavior - Follow AAA pattern: Arrange, Act, Assert
- No force unwrapping (
!) - use proper assertions - Import only necessary modules (
@testable import Anytype)
When Refactoring Production Code
CRITICAL: Always update tests when refactoring:
- Search for test references:
rg "OldClassName" AnyTypeTests/ --type swift
rg "oldPropertyName" AnyTypeTests/ --type swift
-
Update test mocks:
- Check
AnyTypeTests/Mocks/ - Check
Anytype/Sources/PreviewMocks/ - Update DI registrations in
MockView.swift
- Check
-
Update mock extensions:
- Search for
.mock(in test files - Update parameters if initializer changed
- Search for
-
Run tests before committing:
- User will verify in Xcode (faster with caches)
- Report all test file changes to user
Common Test Patterns in Codebase
Pattern 1: Builder Testing
@Test func testBuilderCreatesCorrectModel() {
let input = [...setup...]
let result = builder.build(input)
#expect(result.property1 == expected1)
#expect(result.property2 == expected2)
#expect(result.collection.count == 3)
}
Pattern 2: Storage/Repository Testing
@Suite(.serialized)
struct StorageTests {
init() {
// Setup
---
*Content truncated.*
When not to use it
- →Writing application production logic
- →Refactoring code outside the Swift ecosystem
Prerequisites
Limitations
- →Requires manual implementation of test logic
- →Depends on testable code architecture
How it compares
Promotes specific modern testing patterns (Swift Testing) while enforcing strict coding standards for mocks and assertions.
Compared to similar skills
tests-developer side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| tests-developer (this skill) | 1 | 6mo | Review | Intermediate |
| swiftui-performance-developer | 1 | 6mo | No flags | Intermediate |
| ios-simulator-skill | 27 | 1mo | Review | Advanced |
| build-iphone-apps | 14 | 8mo | Review | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by anyproto
View all by anyproto →You might also like
swiftui-performance-developer
anyproto
Audit and improve SwiftUI runtime performance through code review and Instruments guidance. Use for diagnosing slow rendering, janky scrolling, excessive view updates, or layout thrash in SwiftUI apps.
ios-simulator-skill
conorluddy
21 production-ready scripts for iOS app testing, building, and automation. Provides semantic UI navigation, build automation, accessibility testing, and simulator lifecycle management. Optimized for AI agents with minimal token output.
build-iphone-apps
glittercowboy
Build professional native iPhone apps in Swift with SwiftUI and UIKit. Full lifecycle - build, debug, test, optimize, ship. CLI-only, no Xcode. Targets iOS 26 with iOS 18 compatibility.
xcodebuildmcp
cameroncooke
Official skill for XcodeBuildMCP. Use when doing iOS/macOS/watchOS/tvOS/visionOS work (build, test, run, debug, log, UI automation).
survey-sdk-audit
PostHog
Audit PostHog survey SDK features and version requirements
swift-concurrency-expert
Dimillian
Swift Concurrency review and remediation for Swift 6.2+. Use when asked to review Swift Concurrency usage, improve concurrency compliance, or fix Swift concurrency compiler errors in a feature or file.