testing-patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited testing-patterns (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
A bulleted imperative like {match} tells the agent to never reveal, disclose, or mention something to the user. Used adversarially it can instruct the agent to hide its tool calls or lie about what it did — stripping the transparency a user relies on to trust the agent.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
src/foo.test.ts next to src/foo.ts (primary pattern)*.e2e.test.ts in test/ directory or colocated*.live.test.ts for tests requiring real API keystest/setup.ts for global beforeEach/afterEach hooksvitest.config.ts extended by vitest.unit.config.ts, vitest.e2e.config.ts, vitest.live.config.tsimport { describe, expect, it, vi } from "vitest";
describe("resolvePermission", () => {
it("auto-approves safe tools without prompting", async () => {
const prompt = vi.fn(async () => true);
const res = await resolvePermission(makeRequest(), { prompt });
expect(res).toEqual({ outcome: "allow" });
expect(prompt).not.toHaveBeenCalled();
});
it("prompts for dangerous operations", async () => {
const prompt = vi.fn(async () => true);
await resolvePermission(makeDangerousRequest(), { prompt });
expect(prompt).toHaveBeenCalledTimes(1);
expect(prompt).toHaveBeenCalledWith("exec", "exec: rm -rf /");
});
});// Function mocks for dependency injection
const sendFn = vi.fn(async () => ({ messageId: "test" }));
// Module mocks (use sparingly -- prefer DI)
vi.mock("./network.js", () => ({
fetch: vi.fn().mockResolvedValue({ ok: true }),
}));
// Spy on existing methods
const spy = vi.spyOn(store, "save");
expect(spy).toHaveBeenCalledWith(expectedData);
// Stub environment variables (auto-cleaned with unstubEnvs: true)
vi.stubEnv("API_KEY", "test-key-123");
// Fake timers (guard against leaks in afterEach)
vi.useFakeTimers();
vi.advanceTimersByTime(5000);
// Always restore: vi.useRealTimers()// test/setup.ts
import { afterAll, afterEach, beforeEach, vi } from "vitest";
import { withIsolatedTestHome } from "./test-env.js";
process.env.VITEST = "true";
const testEnv = withIsolatedTestHome(); // Isolated HOME per worker
afterAll(() => testEnv.cleanup());
afterEach(() => {
if (vi.isFakeTimers()) vi.useRealTimers(); // Prevent cross-test leaks
});// Prefer factory functions over raw object literals
function makePermissionRequest(
overrides: Partial<PermissionRequest> = {},
): PermissionRequest {
const base: PermissionRequest = {
sessionId: "session-1",
toolCall: { toolCallId: "tool-1", title: "read: src/index.ts", status: "pending" },
options: [{ kind: "allow_once", optionId: "allow" }],
};
return { ...base, ...overrides };
}// vitest.config.ts
coverage: {
provider: "v8",
reporter: ["text", "lcov"],
all: false, // Only count files exercised by tests
thresholds: { lines: 70, functions: 70, branches: 55, statements: 70 },
include: ["./src/**/*.ts"],
exclude: ["src/**/*.test.ts", "src/cli/**", "src/gateway/**"],
}maxWorkers above 16 (diminishing returns, flaky on CI)vi.mock when dependency injection via function params worksafterEach#[cfg(test)] mod tests at the bottom of each source file (primary pattern)tests/ directory at crate root (rare in workspace projects)[dev-dependencies] of each crate's Cargo.tomlcargo test --lib | Single crate: cargo test -p claudio-gateway --libcargo test --lib test_name_substringcargo test --lib -- --skip concurrent#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn insert_and_get() {
let map = BoundedMap::new(10, Duration::from_secs(60));
assert!(map.insert("a", 1));
assert_eq!(map.get("a"), Some(1));
}
#[test]
fn capacity_enforced() {
let map = BoundedMap::new(3, Duration::from_secs(60));
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
map.insert("d", 4); // should evict one
assert!(map.len() <= 3);
}
#[test]
fn ttl_expiry_on_get() {
let map = BoundedMap::new(10, Duration::from_millis(1));
map.insert("a", 1);
std::thread::sleep(Duration::from_millis(5));
assert_eq!(map.get("a"), None);
}
}#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[tokio::test]
async fn returns_immediately_when_no_tool_calls() {
let provider = Arc::new(MockToolProvider::new(vec![final_response("Hello!")]));
let mut executor = AgentExecutor::new(provider, "http://unused:9999", 10);
let result = executor.execute(test_request()).await.unwrap();
assert_eq!(result.iterations, 1);
assert_eq!(result.tool_calls_made, 0);
}
#[tokio::test]
async fn max_iterations_produces_final_response() {
// Provider always returns tool calls -- should hit max iterations
let provider = Arc::new(MockToolProvider::new(vec![tool_call_response()]));
let mut executor = AgentExecutor::new(provider, "http://unused:9999", 3);
let result = executor.execute(test_request()).await.unwrap();
assert!(result.iterations <= 3);
}
}/// Stub: always returns a fixed response. No network calls.
pub struct StubProvider { provider_name: String }
#[async_trait]
impl Provider for StubProvider {
fn name(&self) -> &str { &self.provider_name }
async fn chat_completion(&self, req: &ChatCompletionRequest)
-> Result<ChatCompletionResponse, ProviderError> {
Ok(ChatCompletionResponse { /* canned fields */ })
}
}
/// Scripted: returns pre-configured responses in sequence.
/// Useful for multi-turn agent loops.
pub struct ScriptedProvider {
responses: std::sync::Mutex<Vec<ChatCompletionResponse>>,
}#[cfg(test)] modules (typical: 100+ test files in a workspace)providers/src/stub.rs)Arc<dyn Trait> for mock injection in async contextscargo test -p crate-name --lib// Minimal inline tests for Tauri commands
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_newer_detects_version_bump() {
assert!(is_newer("1.0.1", "1.0.0"));
assert!(!is_newer("1.0.0", "1.0.0"));
assert!(!is_newer("0.9.9", "1.0.0"));
}
}Projects use the modern Testing framework with @Test macros and #expect assertions.
import Foundation
import Testing
@testable import YourApp
@Suite struct KeychainStoreTests {
@Test func saveLoadUpdateDeleteRoundTrip() {
let service = "com.example.tests.\(UUID().uuidString)"
let account = "value"
#expect(KeychainStore.delete(service: service, account: account))
#expect(KeychainStore.loadString(service: service, account: account) == nil)
#expect(KeychainStore.saveString("first", service: service, account: account))
#expect(KeychainStore.loadString(service: service, account: account) == "first")
}
}@Suite(.serialized) struct GatewayConnectionControllerTests {
@Test @MainActor func resolvedDisplayNameSetsDefaultWhenMissing() {
withUserDefaults([displayKey: nil, "node.instanceId": "ios-test"]) {
let appModel = NodeAppModel()
let controller = GatewayConnectionController(appModel: appModel, startDiscovery: false)
let resolved = controller._test_resolvedDisplayName(defaults: .standard)
#expect(!resolved.isEmpty)
}
}
}@Suite(.serialized) struct VoiceWakeManagerStateTests {
@Test @MainActor func suspendAndResumeCycleUpdatesState() async {
let manager = VoiceWakeManager()
manager.isEnabled = true
manager.isListening = true
let suspended = manager.suspendForExternalAudioCapture()
#expect(suspended == true)
#expect(manager.isListening == false)
manager.resumeAfterExternalAudioCapture(wasSuspended: true)
try? await Task.sleep(nanoseconds: 900_000_000)
#expect(manager.statusText.contains("Voice Wake") == true)
}
}@Observable class directly in the test@MainActor annotation for UI-bound statewithUserDefaults helper that snapshots and restores// In production code, expose test-only accessors:
func _test_resolvedDisplayName(defaults: UserDefaults) -> String { ... }
func _test_currentCaps() -> [String] { ... }
func _test_handleRecognitionCallback(transcript: String?, ...) { ... }actor CaptureBox {
var value: String?
func set(_ next: String) { self.value = next }
}
let capture = CaptureBox()
manager.configure { cmd in await capture.set(cmd) }# Run tests on simulator
xcodebuild test -project App.xcodeproj -scheme App \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro'
# Build only (catches compile errors)
xcodebuild -project App.xcodeproj -scheme App \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' build*_test.go in the same package as the code under testpackage crypto (not package crypto_test) for internal accessgo test ./... | Single package: go test ./internal/crypto/package crypto
import (
"bytes"
"testing"
)
func TestEncryptDecrypt(t *testing.T) {
key := make([]byte, chacha20poly1305.KeySize)
rand.Read(key)
plaintext := []byte("Hello, World!")
encrypted, err := Encrypt(plaintext, key, nil)
if err != nil {
t.Fatalf("Encrypt failed: %v", err)
}
decrypted, err := Decrypt(encrypted, key, nil)
if err != nil {
t.Fatalf("Decrypt failed: %v", err)
}
if !bytes.Equal(decrypted, plaintext) {
t.Errorf("Decrypted text doesn't match.\nGot: %q\nWant: %q", decrypted, plaintext)
}
}func TestEncryptInvalidKey(t *testing.T) {
shortKey := make([]byte, 16)
_, err := Encrypt([]byte("test"), shortKey, nil)
if err == nil {
t.Error("Encrypt should reject short key")
}
}func TestHandshakeClientServer(t *testing.T) {
serverResult := make(chan *HandshakeResult, 1)
serverErr := make(chan error, 1)
server := network.NewServer(handler)
if err := server.Listen("127.0.0.1:0"); err != nil {
t.Fatalf("Failed to listen: %v", err)
}
go server.Serve()
defer server.Close()
conn, err := network.Dial(server.Addr().String())
if err != nil {
t.Fatalf("Failed to dial: %v", err)
}
defer conn.Close()
select {
case err := <-serverErr:
t.Fatalf("Server handshake failed: %v", err)
case result := <-serverResult:
if result.PeerID != "test-client" {
t.Errorf("Server got peer ID = %q, want %q", result.PeerID, "test-client")
}
case <-time.After(2 * time.Second):
t.Fatal("Server handshake timeout")
}
}func TestGenerateKeyUniqueness(t *testing.T) {
k1, _ := GenerateIdentityKey()
k2, _ := GenerateIdentityKey()
if bytes.Equal(k1.PublicKey, k2.PublicKey) {
t.Error("Generated identical public keys (should be unique)")
}
}
func TestFingerprintDeterministic(t *testing.T) {
keypair, _ := GenerateIdentityKey()
f1 := keypair.Fingerprint()
f2 := keypair.Fingerprint()
if f1 != f2 {
t.Error("Fingerprint is not deterministic")
}
}go test -race ./... # Always run in CI| Language | Convention | Example |
|---|---|---|
| TypeScript | describe("module") > it("does X when Y") | it("auto-approves safe tools") |
| Rust | snake_case function names | fn insert_and_get() |
| Swift | camelCase method names on @Suite struct | func saveLoadUpdateDeleteRoundTrip() |
| Go | TestXxx with PascalCase | func TestEncryptDecrypt(t *testing.T) |
/ E2E \ *.e2e.test.ts, Docker scripts
/ Integration \ Server tests, handshake tests
/ Unit Tests \ #[test], @Test, TestXxx, it()Ratio target: ~70% unit, ~20% integration, ~10% e2e.
TypeScript (Vitest):
- name: Test
run: pnpm test
- name: Coverage
run: pnpm test:coverageRust (cargo test):
- name: Test
run: cargo test --lib
- name: Clippy
run: cargo clippy -- -D warningsSwift (xcodebuild):
- name: Test
run: |
xcodebuild test -project App.xcodeproj -scheme App \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro'Go (go test):
- name: Test
run: go test -race -cover ./...| Language | Framework | Run Command | Config File | Convention |
|---|---|---|---|---|
| TypeScript | Vitest 4.x | pnpm test / vitest run | vitest.config.ts | *.test.ts colocated |
| Rust | cargo test | cargo test --lib | Cargo.toml (workspace) | #[cfg(test)] mod tests |
| Swift | Swift Testing | xcodebuild test | .xcodeproj scheme | *Tests.swift in Tests/ |
| Go | go test | go test ./... | None (built-in) | *_test.go same pkg |
| Language | Primary Mock Approach | Avoid |
|---|---|---|
| TypeScript | vi.fn() + dependency injection via params | Heavy vi.mock() of whole modules |
| Rust | Trait-based stubs (StubProvider) | mockall for simple cases |
| Swift | _test_ accessor methods + actor captures | Swizzling, runtime patching |
| Go | Interface-based injection + channels | Monkey patching, reflect |
Use when the function has invariants you can express as a rule (commutativity, round-trip, idempotency, monotonicity). One property test replaces dozens of example cases.
| Language | Library | Quick example |
|---|---|---|
| TypeScript | fast-check | fc.assert(fc.property(fc.string(), s => decode(encode(s)) === s)) |
| Rust | proptest | proptest! { #[test] fn round_trip(s in any::<String>()) { prop_assert_eq!(decode(&encode(&s)), s); } } |
| Swift | swift-testing + manual generators | Loop with Int.random(in:) over #expect |
| Go | testing/quick (stdlib) or gopter | quick.Check(func(s string) bool { return decode(encode(s)) == s }, nil) |
Sweet spots: parsers, codecs, serialization, math utilities, sort/merge logic. Skip for pure I/O wrappers.
| Layer | Target |
|---|---|
| Pure logic, parsers | 90%+ |
| Service / handler code | 70-80% |
| UI / view layer | 40-60% |
| Glue, framework wiring | not measured |
Coverage is a floor, not a goal. 100% line coverage with no assertions on outputs proves nothing.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.