Java testing
Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/java-testing
When to activate: Java testing, JUnit 5, Mockito, AssertJ, Testcontainers, WireMock, Spring MVC test, parameterized testsFrom its SKILL.md
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill java-testingAssembled 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
5.8 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it
Java Testing Patterns
JUnit 5 Basics
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock UserRepository userRepository;
@Mock EmailService emailService;
@InjectMocks UserService userService;
@Test
void findById_returnsUser_whenExists() {
var user = new User(1L, "Alice", "[email protected]");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
var result = userService.findById(1L);
assertThat(result).isEqualTo(user.toDto());
verify(userRepository).findById(1L);
}
@Test
void findById_throwsNotFound_whenMissing() {
when(userRepository.findById(anyLong())).thenReturn(Optional.empty());
assertThatThrownBy(() -> userService.findById(99L))
.isInstanceOf(ResourceNotFoundException.class)
.hasMessageContaining("99");
}
@Nested
class CreateUser {
@Test
void sendsWelcomeEmail_onSuccess() {
when(userRepository.existsByEmail(any())).thenReturn(false);
when(userRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
userService.create(new CreateUserRequest("Bob", "[email protected]"));
verify(emailService).sendWelcome(argThat(u -> "[email protected]".equals(u.getEmail())));
}
}
}
Parameterized Tests
@ParameterizedTest
@CsvSource({
"[email protected], true",
"invalid-email, false",
", false",
"missing@domain, false"
})
void validateEmail(String email, boolean expected) {
assertThat(EmailValidator.isValid(email)).isEqualTo(expected);
}
@ParameterizedTest
@MethodSource("provideOrders")
void calculateTotal(List<OrderItem> items, BigDecimal expected) {
assertThat(orderService.calculateTotal(items)).isEqualByComparingTo(expected);
}
static Stream<Arguments> provideOrders() {
return Stream.of(
Arguments.of(List.of(item(10, 2), item(5, 3)), new BigDecimal("35")),
Arguments.of(List.of(), BigDecimal.ZERO)
);
}
AssertJ Fluent Assertions
// Collections
assertThat(users)
.hasSize(3)
.extracting(User::getName)
.containsExactlyInAnyOrder("Alice", "Bob", "Charlie");
// Exceptions
assertThatThrownBy(() -> service.process(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Input must not be null");
// Soft assertions — all failures reported at once
SoftAssertions.assertSoftly(soft -> {
soft.assertThat(user.getName()).isEqualTo("Alice");
soft.assertThat(user.getEmail()).endsWith("@example.com");
soft.assertThat(user.isActive()).isTrue();
});
Testcontainers
@SpringBootTest
@Testcontainers
class OrderRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("testdb");
@DynamicPropertySource
static void props(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired OrderRepository repository;
@Test
@Transactional
void savesAndRetrievesOrder() {
var order = new Order(/* ... */);
var saved = repository.save(order);
assertThat(repository.findById(saved.getId())).isPresent();
}
}
WireMock
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureWireMock(port = 0)
class PaymentClientTest {
@Autowired PaymentClient paymentClient;
@Test
void chargeCard_returnsSuccess() {
stubFor(post(urlEqualTo("/v1/charges"))
.withRequestBody(matchingJsonPath("$.amount", equalTo("1000")))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("charge-success.json")));
var result = paymentClient.charge(new ChargeRequest("tok_test", 1000));
assertThat(result.getStatus()).isEqualTo("succeeded");
}
}
Spring MVC Test
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired MockMvc mvc;
@MockBean UserService userService;
@Test
void getUser_returns200() throws Exception {
when(userService.findById(1L)).thenReturn(new UserResponse(1L, "Alice"));
mvc.perform(get("/api/v1/users/1").accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Alice"));
}
@Test
void createUser_returns201() throws Exception {
var body = """{"name":"Bob","email":"[email protected]"}""";
when(userService.create(any())).thenReturn(new UserResponse(2L, "Bob"));
mvc.perform(post("/api/v1/users")
.contentType(APPLICATION_JSON)
.content(body))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(2));
}
}
Key Rules
@Nestedclasses group related tests — use them instead of long method name prefixes@ParameterizedTesteliminates copy-paste test methods for boundary conditions- Use
@MockBeanin@WebMvcTest/@SpringBootTest; use@Mock+@ExtendWith(MockitoExtension.class)for pure unit tests - Testcontainers
staticcontainer is reused across test methods in the class — far faster than per-test startup - AssertJ
extracting()is cleaner than mapping to a list and then asserting — use it for collection element checks
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.