agentsclimarketplace

Universal testing

Skill asong56/skills/03-build/universal/universal-testing

Language-agnostic TDD meta-skill. Inject runtime parameters (runtime, test_runner, mock_library, coverage_tool, coverage_gate) to activate language-specific idioms while keeping the core RED → GREEN → REFACTOR philosophy, assertion patterns, and testing tiers constant. Incorporates former: python-testing, kotlin-testing, rust-testing, cpp-testing, golang-testing, react-testing, csharp-testing, fsharp-testing, perl-testing.From its SKILL.md

Install
npx -y skills add asong56/skills --skill universal-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.2 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it

universal-testing

Why This Skill Exists

Nine language-specific testing skills (python-testing, kotlin-testing, rust-testing, cpp-testing, golang-testing, react-testing, csharp-testing, fsharp-testing, perl-testing) shared an identical philosophical core — TDD cycle, assertion strategy, testing tiers, coverage gate — and differed only in tooling names. Per the Three-Principle Framework:

  • Output of language-detection = unique input of per-language test skill, with no other consumer → sequential, single-path workflow → MERGE.
  • Combined token budget (core + one active config block) stays well under 5 K.

test-driven-development (universal/systematic-debugging) remains independent per the Circuit-Breaker rules: it operates under different state transitions and would balloon the prompt past 8 K if merged here.


Runtime Parameters

Call this skill by declaring params at the top of your request or by having the orchestrator inject them:

{
  "skill": "universal-testing",
  "params": {
    "runtime":        "Python",
    "test_runner":    "pytest",
    "mock_library":   "pytest-mock / unittest.mock",
    "coverage_tool":  "pytest-cov",
    "coverage_gate":  "80%"
  }
}

Quick-reference param table

runtimetest_runnermock_librarycoverage_toolCoverage default
Pythonpytestpytest-mock / unittest.mockpytest-cov80%
KotlinKotestMockKKover80%
Rustcargo test / nextestmockallcargo-llvm-cov80%
C++GoogleTest / CTestGoogleMockgcov / llvm-cov80%
Gogo testtestify/mockgo tool cover80%
React/TSVitest or Jest + RTLmswv8 / istanbul80%
C#xUnitNSubstitute / MoqCoverlet80%
F#xUnit + FsUnitNSubstituteCoverlet80%
Perlprove + Test2::V0Test::MockModuleDevel::Cover80%

If runtime is not provided, infer it from the file extension or import statements in the code under review. If still ambiguous, ask before proceeding.


Core Philosophy (Runtime-Invariant)

These rules apply regardless of language:

  1. Test behavior, not implementation. Tests assert outcomes observable from the public API — not internal state, private methods, or call counts unless the call itself is the contract.
  2. Isolate the unit. Use the declared mock_library to replace all collaborators (I/O, network, time, randomness) so tests are deterministic and fast.
  3. Coverage gate is a floor, not a goal. Hitting coverage_gate with trivial assertions is worse than 60% coverage with meaningful assertions. Critical paths require 100% branch coverage regardless of the gate.
  4. Tests are first-class code. Apply the same naming, clarity, and refactoring standards as production code.

The RED → GREEN → REFACTOR Cycle

┌─────────────────────────────────────────────────────────┐
│  1. RED    Write a failing test that expresses the      │
│            desired behavior. Run it; confirm it fails   │
│            for the right reason (not a syntax error).   │
│                          ↓                              │
│  2. GREEN  Write the minimum code to make the test      │
│            pass. Resist the urge to generalize yet.     │
│                          ↓                              │
│  3. REFACTOR  Improve the implementation while keeping  │
│               all tests green. Remove duplication,      │
│               clarify names, extract concepts.          │
│                          ↓                              │
│  4. REPEAT  Move to the next behavior unit.             │
└─────────────────────────────────────────────────────────┘

Testing Tiers

Apply these tiers in every runtime. The ratio guideline is the Testing Pyramid: many unit → fewer integration → few E2E.

Tier 1 — Unit Tests

  • Test a single function / method / class in complete isolation.
  • All external collaborators are replaced with mock_library doubles.
  • Must run in < 1 ms each; no network, no filesystem, no clock.
  • Naming: test_<unit>_<scenario>_<expected_outcome> (adapt to language convention — e.g. Go uses TestUnitScenario, Kotlin uses "unit - scenario" in Kotest).

Tier 2 — Integration Tests

  • Test the interaction between two or more real components (e.g., service + real database via Testcontainers, or HTTP client + real server on localhost).
  • Use factories or fixtures to build test data; never depend on pre-seeded production data.
  • Acceptable runtime: seconds, not minutes. Parallelize where safe.

Tier 3 — Contract / API Tests

  • Assert the public interface contract of a module or service.
  • Provider-side: verify your outputs match consumer expectations.
  • Consumer-side: verify you handle all provider response shapes.

Tier 4 — End-to-End / UI Tests

  • Exercise the full stack through a browser or CLI entry point.
  • Reserve for critical user journeys only (login, checkout, core happy path).
  • Treat flakiness as a P1 defect: flaky E2E tests erode trust in the entire suite.

Language-Specific Activation Blocks

Load only the block matching the active runtime. Ignore all others.


🐍 Python (pytest)

# Run all tests with coverage
pytest --cov={package} --cov-report=term-missing --cov-report=html

# Run a single test file
pytest tests/unit/test_service.py -v

# Run with parallel execution
pytest -n auto

Fixture pattern:

import pytest

@pytest.fixture
def user_service(mocker):
    repo = mocker.Mock(spec=UserRepository)
    return UserService(repo)

def test_find_user_returns_none_when_not_found(user_service, mocker):
    mocker.patch.object(user_service._repo, "get", return_value=None)
    assert user_service.find("[email protected]") is None

Parametrize pattern:

@pytest.mark.parametrize("email,valid", [
    ("[email protected]", True),
    ("bad-email", False),
    ("", False),
])
def test_email_validation(email, valid):
    assert validate_email(email) == valid

Coverage gate command:

pytest --cov={package} --cov-fail-under=80

🟣 Kotlin (Kotest + MockK)

// FunSpec example (preferred for unit tests)
class UserServiceTest : FunSpec({
    val repo = mockk<UserRepository>()
    val service = UserService(repo)

    test("returns null when user not found") {
        every { repo.findByEmail("[email protected]") } returns null
        service.find("[email protected]") shouldBe null
    }
})

Coroutine testing:

test("suspends until result is ready") {
    coEvery { repo.fetchAsync(any()) } returns User("alice")
    runTest { service.fetchUser("alice") shouldBe User("alice") }
}

Coverage gate command:

./gradlew koverVerify   # fails build if < 80%

🦀 Rust (cargo test + mockall)

#[cfg(test)]
mod tests {
    use super::*;
    use mockall::predicate::*;

    #[test]
    fn returns_error_on_missing_user() {
        let mut repo = MockUserRepository::new();
        repo.expect_find().with(eq("ghost")).returning(|_| None);
        let svc = UserService::new(repo);
        assert!(svc.get_user("ghost").is_err());
    }
}

Async test:

#[tokio::test]
async fn fetch_user_resolves() {
    // ...
}

Coverage gate command:

cargo llvm-cov --fail-under-lines 80

⚙️ C++ (GoogleTest + GoogleMock)

// CMakeLists.txt: add_executable(tests ...) + target_link_libraries(tests GTest::gtest_main gmock)

TEST(UserServiceTest, ReturnsFalseWhenUserNotFound) {
    MockUserRepository repo;
    EXPECT_CALL(repo, FindByEmail("[email protected]")).WillOnce(Return(std::nullopt));
    UserService svc{repo};
    EXPECT_FALSE(svc.Find("[email protected]").has_value());
}

Parametrized test:

INSTANTIATE_TEST_SUITE_P(
    EmailValidation, EmailTest,
    testing::Values(
        std::make_tuple("[email protected]", true),
        std::make_tuple("bad", false)
    )
);

Coverage gate command:

cmake -DCMAKE_BUILD_TYPE=Coverage .. && make && ctest
lcov --summary coverage.info | grep "lines"   # manual check against gate

🐹 Go (go test + testify)

func TestUserService_Find_ReturnsNilWhenMissing(t *testing.T) {
    repo := new(MockUserRepository)
    repo.On("FindByEmail", "[email protected]").Return(nil, nil)
    svc := NewUserService(repo)
    result, err := svc.Find("[email protected]")
    assert.NoError(t, err)
    assert.Nil(t, result)
}

Table-driven pattern (idiomatic Go):

tests := []struct{ email string; want bool }{
    {"[email protected]", true},
    {"bad", false},
}
for _, tc := range tests {
    t.Run(tc.email, func(t *testing.T) {
        assert.Equal(t, tc.want, ValidateEmail(tc.email))
    })
}

Coverage gate command:

go test ./... -coverprofile=coverage.out
go tool cover -func=coverage.out | grep total   # check vs gate manually

⚛️ React / TypeScript (Vitest + RTL + MSW)

// Test what the user sees, not implementation details
test("shows error message on login failure", async () => {
    server.use(http.post("/api/login", () => HttpResponse.json({ error: "Bad credentials" }, { status: 401 })));
    render(<LoginForm />, { wrapper: Providers });
    await userEvent.type(screen.getByLabelText(/email/i), "[email protected]");
    await userEvent.click(screen.getByRole("button", { name: /log in/i }));
    expect(await screen.findByRole("alert")).toHaveTextContent(/bad credentials/i);
});

Accessibility assertion:

test("form has no accessibility violations", async () => {
    const { container } = render(<LoginForm />, { wrapper: Providers });
    const results = await axe(container);
    expect(results).toHaveNoViolations();
});

Coverage gate command:

vitest run --coverage --coverage.thresholds.lines=80

🔷 C# (xUnit + NSubstitute + Coverlet)

public class UserServiceTests
{
    [Fact]
    public async Task FindAsync_ReturnsNull_WhenUserNotFound()
    {
        var repo = Substitute.For<IUserRepository>();
        repo.FindByEmailAsync("[email protected]").Returns((User?)null);
        var svc = new UserService(repo);
        var result = await svc.FindAsync("[email protected]");
        result.Should().BeNull();
    }

    [Theory]
    [InlineData("[email protected]", true)]
    [InlineData("bad", false)]
    public void ValidateEmail_ReturnsExpected(string email, bool expected) =>
        EmailValidator.IsValid(email).Should().Be(expected);
}

Coverage gate command:

dotnet test /p:CollectCoverage=true /p:Threshold=80

🟦 F# (xUnit + FsUnit + FsCheck)

[<Fact>]
let ``find returns None when user missing`` () =
    let repo = Substitute.For<IUserRepository>()
    repo.FindByEmail("[email protected]").Returns(None) |> ignore
    let svc = UserService(repo)
    svc.Find("[email protected]") |> should equal None

// Property-based test with FsCheck
[<Property>]
let ``non-empty strings are never equal to None result`` (email: NonEmptyString) =
    // ...

🐪 Perl (Test2::V0 + prove)

use Test2::V0;
use Test::MockModule;

my $mock = mock 'UserRepository' => (
    override => [find_by_email => sub { undef }],
);
my $svc = UserService->new(repo => UserRepository->new);
is $svc->find("ghost\@x.com"), undef, "returns undef when user not found";
done_testing;

Coverage gate command:

cover -test -report html
# Check Devel::Cover output for statement coverage >= 80%

Workflow Checklist

Before marking a TDD cycle complete, verify:

  • Test name clearly describes scenario and expected outcome
  • Test fails (RED) before implementation is written
  • Test passes (GREEN) with minimal implementation
  • No implementation details leaked into assertions
  • All external I/O is mocked / stubbed
  • Edge cases covered: null/empty input, boundary values, error paths
  • coverage_tool run; gate met or gap documented with rationale
  • Test is deterministic: passes identically on first and hundredth run

Migration Notes

Deprecated skillReplaced byruntime param
python-testinguniversal-testing"Python"
kotlin-testinguniversal-testing"Kotlin"
rust-testinguniversal-testing"Rust"
cpp-testinguniversal-testing"C++"
golang-testinguniversal-testing"Go"
react-testinguniversal-testing"React/TS"
csharp-testinguniversal-testing"C#"
fsharp-testinguniversal-testing"F#"
perl-testinguniversal-testing"Perl"

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.