ワンクリックで
writing-unit-tests
Writes unit tests using XCTest and Cuckoo mocks following project testing patterns. Use when creating or adding tests.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Writes unit tests using XCTest and Cuckoo mocks following project testing patterns. Use when creating or adding tests.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Standard editorial template for any standalone HTML output (reports, RCAs, dashboards, diagrams, slides, recaps). Use EVERY time you generate an HTML file so output follows one consistent house style instead of ad-hoc theming.
Findings-first review agent for code changes. Use when the user asks to review a branch, PR, diff, commit range, or recent changes and wants prioritized, actionable issues instead of implementation work.
Scan and clean stale Claude Code sessions from the shared store at ~/.local/share/claude/projects (used by all .claude / .claude-accountN dirs via symlink). Removes session JSONLs older than N days, orphan subagent dirs, and reports reclaimable space.
Triage ShopHelp XCTest/Swift Testing failures before proposing fixes.
Manage Jira issues through jhelp shell functions (jv, jm, jd, jc, jforward, etc.). Use when the user wants to view, transition, assign, comment on, edit, search, or create Jira work items; when they provide a bare issue number, Jira issue key, or Jira URL; or when the task involves the current git branch ticket.
Create git commits. Use when user says "commit", "commit this", "commit changes", "split commit", "split commit change", "split the changes".
| name | writing-unit-tests |
| description | Writes unit tests using XCTest and Cuckoo mocks following project testing patterns. Use when creating or adding tests. |
Writes unit tests following ShopHelp's XCTest + Cuckoo patterns.
Tests mirror the main app structure in ShopHelpTests/:
| Source | Test |
|---|---|
ShopHelp/Presentation/{Feature}/{Feature}ViewModel.swift | ShopHelpTests/Presentation/{Feature}ViewModelTests.swift |
ShopHelp/Domain/UseCases/{Action}{Entity}UseCase.swift | ShopHelpTests/Domain/{Action}{Entity}UseCaseTests.swift |
ShopHelp/Data/Repositories/{Entity}RepositoryImpl.swift | ShopHelpTests/Data/{Entity}RepositoryTests.swift |
//
// {Name}Tests.swift
// ShopHelp
//
// Created by Man Tran on DD/MM/YY.
//
import XCTest
import Cuckoo
@testable import ShopHelp
@MainActor
final class {Name}Tests: XCTestCase {
private var sut: {ClassUnderTest}!
private var mockDependency: Mock{DependencyProtocol}!
override func setUp() {
super.setUp()
mockDependency = Mock{DependencyProtocol}()
sut = {ClassUnderTest}(dependency: mockDependency)
}
override func tearDown() {
sut = nil
mockDependency = nil
super.tearDown()
}
func test_{methodName}_{scenario}_{expectedResult}() async {
// Given
stub(mockDependency) { stub in
when(stub.someMethod()).thenReturn(expectedValue)
}
// When
await sut.methodUnderTest()
// Then
XCTAssertEqual(sut.state, .loaded(expectedValue))
verify(mockDependency).someMethod()
}
}
test_{methodName}_{scenario}_{expectedResult}
Examples:
test_loadData_success_stateIsLoadedtest_loadData_networkError_stateIsErrortest_addToCart_emptyCart_addsItemtest_execute_invalidInput_throwsError// Return value
stub(mockRepository) { stub in
when(stub.fetchProduct(id: any())).thenReturn(mockProduct)
}
// Throw error
stub(mockRepository) { stub in
when(stub.fetchProduct(id: any())).thenThrow(NetworkError.timeout)
}
// Async return
stub(mockUseCase) { stub in
when(stub.execute()).thenReturn(mockResult)
}
// Verify called
verify(mockRepository).fetchProduct(id: equal(to: "123"))
// Verify called N times
verify(mockRepository, times(2)).fetchProduct(id: any())
// Verify never called
verify(mockRepository, never()).deleteProduct(id: any())
Mocks are generated by Cuckoo from protocol files:
./run [source files]
Generated mocks go to ShopHelpTests/GeneratedMocks.swift.
@MainActor
final class MyViewModelTests: XCTestCase {
private var sut: MyViewModel!
private var mockUseCase: MockMyUseCaseProtocol!
override func setUp() {
super.setUp()
mockUseCase = MockMyUseCaseProtocol()
let dependencies = MyDependencies(useCase: mockUseCase)
sut = MyViewModel(dependencies: dependencies)
}
func test_loadData_success_stateIsLoaded() async {
stub(mockUseCase) { stub in
when(stub.execute()).thenReturn(mockData)
}
await sut.loadData()
XCTAssertEqual(sut.state, .loaded(mockData))
}
func test_loadData_failure_stateIsError() async {
stub(mockUseCase) { stub in
when(stub.execute()).thenThrow(TestError.generic)
}
await sut.loadData()
XCTAssertEqual(sut.state, .error)
XCTAssertNotNil(sut.errorMessage)
}
}
@MainActor
final class GetProductUseCaseTests: XCTestCase {
private var sut: GetProductUseCase!
private var mockRepository: MockProductRepositoryProtocol!
override func setUp() {
super.setUp()
mockRepository = MockProductRepositoryProtocol()
sut = GetProductUseCase(repository: mockRepository)
}
func test_execute_validId_returnsProduct() async throws {
stub(mockRepository) { stub in
when(stub.fetchProduct(id: any())).thenReturn(mockProduct)
}
let result = try await sut.execute(productId: "123")
XCTAssertEqual(result.id, "123")
}
}
make unit-test # All unit tests
make test # All tests (unit + UI)
Single test class:
xcodebuild test \
-project ShopHelp.xcodeproj \
-scheme ShopHelp \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:ShopHelpTests/TestClassName \
CODE_SIGNING_ALLOWED=NO
@MainActor final class + XCTestCasetest_{method}_{scenario}_{expected}async/async throws./run if new protocolSee ShopHelpTests/ for existing test examples.
See docs/SETUP.md for test commands and mock generation.