Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Java Clean Tests

ASecurity

Enforces test quality in Java with JUnit 5 and AssertJ — one concept per test, boundary coverage, fast isolated tests, parameterised cases, and no disabled tests without a reason. Use when writing or reviewing Java tests, and when the user mentions JUnit, AssertJ, Mockito, Testcontainers, @ParameterizedTest, @Disabled, flaky tests, coverage gaps, or asks "how should I test this".

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentgojavadatabase

Security Analysis

A100/100

Scanned 9/19/2026

$npx -y skills add CasLubbers/code-design-skills --skill java-clean-tests --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Java Clean Tests?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Java Clean Tests
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/caslubbers-java-clean-tests/badge)](https://www.skillsdirectory.com/skills/caslubbers-java-clean-tests)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: java-clean-tests
description: Enforces test quality in Java with JUnit 5 and AssertJ — one concept per test, boundary coverage, fast isolated tests, parameterised cases, and no disabled tests without a reason. Use when writing or reviewing Java tests, and when the user mentions JUnit, AssertJ, Mockito, Testcontainers, @ParameterizedTest, @Disabled, flaky tests, coverage gaps, or asks "how should I test this".
---

# Clean tests in Java

Test code is production code. It is read more often than the code it covers, because it is read whenever the code breaks.

## Name the behaviour

The name is the failure report.

```java
// Bad
@Test void test1() { ... }
@Test void testWithdraw() { ... }

// Good
@Test void withdrawFailsWhenBalanceIsInsufficient() { ... }
@Test void withdrawLeavesBalanceUnchangedWhenItFails() { ... }
```

`@DisplayName` carries a full sentence where the method name gets unwieldy, and `@Nested` groups cases around one scenario.

## One concept per test

```java
// Bad — three unrelated assertions; the first failure hides the rest
@Test void testOrder() {
    assertThat(order.total()).isEqualTo(euros(100));
    assertThat(order.status()).isEqualTo(PENDING);
    assertThat(order.items()).hasSize(3);
}

// Good — one reason to fail each
@Test void totalSumsItemPrices() { ... }
@Test void newOrderStartsPending() { ... }
```

Several assertions about *one* concept are fine — `assertThat(order).extracting(...)`, or `assertAll` when you want every field reported at once. The rule is one reason to fail, not one assertion statement.

## Arrange, act, assert

Three visible blocks, separated by a blank line. If arrange runs to twenty lines, the class under test needs too much to exist — that is a design signal, not a test problem.

```java
@Test
void withdrawFailsWhenBalanceIsInsufficient() {
    var account = new Account(euros(50));                       // arrange

    var thrown = catchThrowable(() -> account.withdraw(euros(100)));  // act

    assertThat(thrown).isInstanceOf(InsufficientFundsException.class) // assert
        .hasMessageContaining("50");
    assertThat(account.balance()).isEqualTo(euros(50));
}
```

## AssertJ over bare assertions

Fluent assertions produce failure messages that say what was expected and what arrived, including for collections and exceptions:

```java
assertThat(users).extracting(User::email).containsExactly("a@x.com", "b@x.com");
assertThatThrownBy(() -> parse("")).isInstanceOf(ParseException.class);
assertThat(result).usingRecursiveComparison().isEqualTo(expected);
```

`assertEquals(expected, actual)` with no message tells you two values differed and nothing else.

## Parameterise repeated cases

```java
@ParameterizedTest
@CsvSource({
    "0,    0,   valid boundary",
    "-1,   0,   negative rejected",
    "1001, 0,   above maximum rejected"
})
void clampsToRange(int input, int expected, String description) { ... }
```

`@ValueSource`, `@CsvSource`, `@EnumSource`, and `@MethodSource` cover most tables. Adding a case becomes one line.

## Test the boundaries

The happy path is the case least likely to break. Cover empty and single-element collections, zero, negative, maximum, off-by-one at both ends, null where accepted, duplicate entries, and the first and last iteration. When you fix a bug, write the test that would have caught it, then test around it — bugs cluster.

## Fast, isolated, repeatable

A unit test does no real I/O: no database, no network, no sleeping, no clock. Inject a `Clock` rather than calling `Instant.now()`, and a fake repository rather than a real one. Tests must pass in any order and in parallel, which means no shared static state and no dependence on a previous test's writes.

Where a real dependency is the point, use Testcontainers and label it an integration test so the fast suite stays fast.

## Mock what you own, at the boundary

Mock the interfaces you defined for external systems. Do not mock value objects, collections, or the type under test, and do not assert on interactions when you can assert on results — `verify` on every call turns the test into a copy of the implementation, which then breaks on every refactor.

```java
// Prefer a stub returning data
when(userRepository.findById("42")).thenReturn(Optional.of(alice));

// Over asserting the call happened
verify(userRepository).findById("42");   // only when the call itself is the behaviour
```

## No disabled tests without a reason

```java
// Bad
@Disabled
@Test void reconcilesLedger() { ... }

// Good
@Disabled("PLAT-1182: flaky until the fixture clock is injected")
@Test void reconcilesLedger() { ... }
```

A silently disabled test is a lie about coverage. Fix it, delete it, or say why it sleeps and when it wakes.

## Flakiness is a bug

An intermittent failure is a real defect — usually a race, a shared fixture, or a dependence on wall-clock time. Retrying it hides a bug your users will hit. Fix the cause.

## Coverage is a map, not a target

Use it to find untested branches. Chasing a percentage produces tests that execute code and assert nothing.

Attribution

CasLubbersCasLubbers
View sourceSee grades on GitHubMore from CasLubbers →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

285172 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

10341 votes
View all in development →