agentsclimarketplace

Junit testing

Skill VersoXBT/claude-initial-setup/skills/java/junit-testing

75 skills, 14 agents, 15 commands for Claude Code. Plug-and-play starter kit covering TypeScript, Python, Go, Rust, React, Next.js, FastAPI, Django, Docker, CI/CD, security, testing, and more. Cross-AI support for Cursor, Copilot, and Codex.

Install
npx -y skills add VersoXBT/claude-initial-setup --skill junit-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

  • 4 stars4 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.

What its author says it does

Copied from the file, not written here

JUnit 5 testing patterns including annotations, Mockito mocking, Spring Boot test slices, MockMvc, Testcontainers integration, and parameterized tests. Use when the user is writing Java tests, setting up test infrastructure, mocking dependencies, testing Spring controllers, or running integration tests with real databases. Trigger on any mention of JUnit, Mockito, @SpringBootTest, MockMvc, Testcontainers, or Java testing.

SKILL.md

8.2 KB, as published. Nobody here has run it

JUnit 5 Testing Patterns

Patterns for writing effective unit, integration, and slice tests in Java.

When to Use

  • User is writing JUnit 5 tests
  • User needs to mock dependencies with Mockito
  • User asks about Spring Boot test slices (@WebMvcTest, @DataJpaTest)
  • User wants integration tests with real databases (Testcontainers)
  • User needs parameterized tests for multiple inputs

Core Patterns

JUnit 5 Annotations and Lifecycle

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;

class UserServiceTest {
    private UserService userService;
    private UserRepository userRepository;

    @BeforeEach
    void setUp() {
        userRepository = new InMemoryUserRepository();
        userService = new UserService(userRepository);
    }

    @Test
    @DisplayName("creates a user with valid input")
    void createsUserWithValidInput() {
        User result = userService.createUser(new CreateUserRequest("Alice", "[email protected]"));
        assertAll(
            () -> assertNotNull(result.getId()),
            () -> assertEquals("Alice", result.getName()),
            () -> assertEquals("[email protected]", result.getEmail())
        );
    }

    @Test
    @DisplayName("throws when email is already taken")
    void throwsWhenEmailTaken() {
        userRepository.save(new User("Bob", "[email protected]"));
        assertThrows(ConflictException.class,
            () -> userService.createUser(new CreateUserRequest("Bob2", "[email protected]")));
    }

    @Nested
    @DisplayName("when user exists")
    class WhenUserExists {
        private User existingUser;

        @BeforeEach
        void setUp() {
            existingUser = userRepository.save(new User("Alice", "[email protected]"));
        }

        @Test
        void findsById() {
            Optional<User> found = userService.findById(existingUser.getId());
            assertTrue(found.isPresent());
            assertEquals("Alice", found.get().getName());
        }
    }
}

Mockito -- Mocking Dependencies

Isolate the unit under test by mocking its collaborators.

import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    @Mock private OrderRepository orderRepository;
    @Mock private PaymentGateway paymentGateway;
    @InjectMocks private OrderService orderService;

    @Test
    @DisplayName("places order and charges payment")
    void placesOrderAndChargesPayment() {
        var order = new Order("product-1", 2, 29_99L);
        when(orderRepository.save(any(Order.class))).thenReturn(order);
        when(paymentGateway.charge(anyLong())).thenReturn(new PaymentResult(true, "txn-123"));

        assertNotNull(orderService.placeOrder(order));
        verify(paymentGateway).charge(29_99L);
        verify(orderRepository).save(order);
    }

    @Test
    @DisplayName("rolls back order when payment fails")
    void rollsBackWhenPaymentFails() {
        when(paymentGateway.charge(anyLong())).thenReturn(new PaymentResult(false, null));
        assertThrows(PaymentFailedException.class,
            () -> orderService.placeOrder(new Order("product-1", 1, 50_00L)));
        verify(orderRepository, never()).save(any());
    }
}

@WebMvcTest -- Controller Slice Tests

Test controllers in isolation without starting the full application context. Only the web layer is loaded.

@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired private MockMvc mockMvc;
    @MockBean private UserService userService;

    @Test
    @DisplayName("GET /api/v1/users/{id} returns user")
    void getUser() throws Exception {
        when(userService.findById("1"))
            .thenReturn(Optional.of(new UserResponse("1", "Alice", "[email protected]")));

        mockMvc.perform(get("/api/v1/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.data.name").value("Alice"));
    }

    @Test
    @DisplayName("POST /api/v1/users validates request body")
    void validateCreateUser() throws Exception {
        mockMvc.perform(post("/api/v1/users")
                .contentType("application/json")
                .content("{\"name\":\"\",\"email\":\"not-an-email\"}"))
            .andExpect(status().isBadRequest());
    }
}

Testcontainers -- Integration Tests with Real Databases

Spin up real database containers for integration tests. Tests are reliable and match production behavior.

@SpringBootTest
@Testcontainers
class UserRepositoryIntegrationTest {
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
        .withDatabaseName("testdb").withUsername("test").withPassword("test");

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired private UserRepository userRepository;

    @Test
    @DisplayName("persists and retrieves a user")
    void persistsAndRetrieves() {
        User saved = userRepository.save(new User("Alice", "[email protected]"));
        Optional<User> found = userRepository.findById(saved.getId());
        assertTrue(found.isPresent());
        assertEquals("Alice", found.get().getName());
    }
}

Parameterized Tests

Run the same test logic with different inputs. Reduces duplication.

class EmailValidatorTest {
    private final EmailValidator validator = new EmailValidator();

    @ParameterizedTest
    @CsvSource({"[email protected], true", "[email protected], true", "invalid, false", "@no-local.com, false"})
    void validatesEmail(String email, boolean expected) {
        assertEquals(expected, validator.isValid(email));
    }

    @ParameterizedTest
    @NullAndEmptySource
    @ValueSource(strings = {"   ", "\t"})
    void rejectsBlankEmails(String email) {
        assertFalse(validator.isValid(email));
    }

    @ParameterizedTest
    @MethodSource("validEmailProvider")
    void acceptsValidEmails(String email) { assertTrue(validator.isValid(email)); }

    static Stream<String> validEmailProvider() {
        return Stream.of("[email protected]", "[email protected]", "[email protected]");
    }
}

Anti-Patterns

  • Testing implementation details -- Verifying private method calls or internal state. Test behavior (inputs and outputs), not how the code achieves the result.
  • Overusing @SpringBootTest -- Loads the entire application context. Slow. Use slice annotations (@WebMvcTest, @DataJpaTest) to load only what you need.
  • Not using @ExtendWith(MockitoExtension.class) -- Forgetting this means @Mock and @InjectMocks annotations are silently ignored, leading to NullPointerException.
  • Sharing mutable state between tests -- Tests must be independent. Use @BeforeEach to reset state. Never rely on test execution order.
  • Mocking everything including the class under test -- Only mock collaborators. The class under test should use its real implementation.

Quick Reference

CategoryKey APIs
Lifecycle@BeforeEach, @AfterEach, @BeforeAll, @AfterAll, @Nested
AssertionsassertEquals, assertTrue, assertThrows, assertAll, assertTimeout
Mockitowhen().thenReturn(), verify(), any(), @Mock, @InjectMocks
Slices@WebMvcTest (controllers), @DataJpaTest (JPA), @SpringBootTest (full)
Parameterized@CsvSource, @ValueSource, @MethodSource, @NullAndEmptySource

Keep looking

Skills are one crate of 328,083. 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.