api-contract-review
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks…
Write high-quality JUnit 5 tests with AssertJ assertions. Use when user says "add tests", "write tests", "improve test coverage", or when reviewing/creating test classes for Java code.
Claude Code
$ npx -y skills add decebals/claude-code-java --skill test-quality --agent claude-code
Codex
$ npx skills add decebals/claude-code-java --skill test-quality -a codex -y
Cursor
$ npx skills add decebals/claude-code-java --skill test-quality -a cursor -y
Gemini CLI
$ npx skills add decebals/claude-code-java --skill test-quality -a gemini-cli -y
GitHub Copilot
$ npx skills add decebals/claude-code-java --skill test-quality -a github-copilot -y
OpenCode
$ npx skills add decebals/claude-code-java --skill test-quality -a opencode -y
Windsurf
$ npx skills add decebals/claude-code-java --skill test-quality -a windsurf -y
name: test-quality description: Write high-quality JUnit 5 tests with AssertJ assertions. Use when user says "add tests", "write tests", "improve test coverage", or when reviewing/creating test classes for Java code. license: MIT
Write high-quality, maintainable tests for Java projects using modern best practices.
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import static org.assertj.core.api.Assertions.*;
✅ **Use AssertJ**:
assertThat(plugin.getState())
.as("Plugin should be started after initialization")
.isEqualTo(PluginState.STARTED);
assertThat(plugins)
.hasSize(3)
.extracting(Plugin::getId)
.containsExactly("plugin1", "plugin2", "plugin3");❌ **Avoid JUnit assertions**:
assertEquals(PluginState.STARTED, plugin.getState()); // Less readable assertTrue(plugins.size() == 3); // Less descriptive failures
Always use Arrange-Act-Assert pattern:
@Test
@DisplayName("Should load plugin from valid directory")
void shouldLoadPluginFromValidDirectory() {
// Arrange - Setup test data and dependencies
Path pluginDir = Paths.get("test-plugins/valid-plugin");
PluginLoader loader = new DefaultPluginLoader();
// Act - Execute the behavior being tested
Plugin plugin = loader.load(pluginDir);
// Assert - Verify results
assertThat(plugin)
.isNotNull()
.extracting(Plugin::getId, Plugin::getVersion)
.containsExactly("test-plugin", "1.0.0");
}// Class under test: PluginManager PluginManagerTest // ✅ Simple, standard PluginManagerShould // ✅ BDD style (if team prefers) TestPluginManager // ❌ Avoid
**Option 1: should_expectedBehavior_when_condition** (descriptive)
@Test
void should_throwException_when_pluginDirectoryNotFound() { }
@Test
void should_returnEmptyList_when_noPluginsAvailable() { }
@Test
void should_loadPluginsInDependencyOrder_when_multipleDependencies() { }**Option 2: Natural language with @DisplayName** (cleaner code)
@Test
@DisplayName("Should load all plugins from directory")
void loadAllPlugins() { }
@Test
@DisplayName("Should throw exception when plugin descriptor is invalid")
void invalidPluginDescriptor() { }// Basic collection checks
assertThat(plugins)
.isNotEmpty()
.hasSize(2)
.doesNotContainNull();
// Advanced filtering and extraction
assertThat(plugins)
.filteredOn(p -> p.getState() == PluginState.STARTED)
.extracting(Plugin::getId)
.containsExactlyInAnyOrder("plugin-a", "plugin-b");
// All elements match condition
assertThat(plugins)
.allMatch(p -> p.getVersion() != null, "All plugins have version");// Basic exception check
assertThatThrownBy(() -> loader.load(invalidPath))
.isInstanceOf(PluginException.class)
.hasMessageContaining("Invalid plugin descriptor");
// Detailed exception verification
assertThatThrownBy(() -> manager.startPlugin("missing-plugin"))
.isInstanceOf(PluginException.class)
.hasMessageContaining("Plugin not found")
.hasCauseInstanceOf(IllegalArgumentException.class);
// With assertThatExceptionOfType (more readable)
assertThatExceptionOfType(PluginException.class)
.isThrownBy(() -> loader.load(invalidPath))
.withMessageContaining("Invalid")
.withMessageMatching("Invalid .* descriptor");// Extract and verify multiple properties
assertThat(plugin)
.isNotNull()
.extracting("id", "version", "state")
.containsExactly("my-plugin", "1.0", PluginState.STARTED);
// Using method references (type-safe)
assertThat(plugin)
.extracting(Plugin::getId, Plugin::getVersion, Plugin::getState)
.containsExactly("my-plugin", "1.0", PluginState.STARTED);
// Field by field comparison
assertThat(actualPlugin)
.usingRecursiveComparison()
.isEqualTo(expectedPlugin);@Test
void shouldHaveValidPluginDescriptor() {
SoftAssertions softly = new SoftAssertions();
softly.assertThat(descriptor.getId())
.as("Plugin ID")
.isNotBlank()
.matches("[a-z0-9-]+");
softly.assertThat(descriptor.getVersion())
.as("Plugin version")
.matches("\\d+\\.\\d+\\.\\d+");
softly.assertThat(descriptor.getDependencies())
.as("Dependencies")
.isNotNull()
.doesNotContainNull();
softly.assertAll(); // All assertions evaluated, even if some fail
}assertThat(errorMessage)
.startsWith("Error:")
.contains("plugin", "failed")
.doesNotContain("success")
.matches("Error: .* failed")
.hasLineCount(3);@DisplayName("PluginManager")
class PluginManagerTest {
private PluginManager manager;
@BeforeEach
void setUp() {
manager = new DefaultPluginManager();
}
@Nested
@DisplayName("when starting plugins")
class WhenStartingPlugins {
@Test
@DisplayName("should start all plugins in dependency order")
void shouldStartInDependencyOrder() {
// Test implementation
}
@Test
@DisplayName("should skip disabled plugins")
void shouldSkipDisabledPlugins() {
// Test implementation
}Agent Skills for Java projects, following the open Agent Skills specification This project is not affiliated with Anthropic.
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks…
Analyze Java project architecture at macro level - package structure, module boundaries, dependency direction, and layering. Use…
Generate changelogs from git commits. Use when user says "generate changelog", "update changelog", "what changed since last…
Clean Code principles (DRY, KISS, YAGNI), naming, function design and readability. Use when code is hard to read, with long…
Review Java concurrency code for thread safety, race conditions, deadlocks, and modern patterns (Virtual Threads,…
Common design patterns with Java examples (Factory, Builder, Strategy, Observer, Decorator, etc.). Use when user asks "implement…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.