| name | insurance-testing |
| description | Detailed testing standards for persistence, service, and controller layers |
When to use
Use this skill when creating or modifying tests in this project.
Core principles
- Use AAA structure in every test.
- Keep Act phase to one line in unit tests.
- Keep tests deterministic (no hidden time/env/network dependencies).
- Use descriptive method names that state scenario and expected behavior.
- Pick the narrowest useful test type:
- unit tests for pure business logic,
- slice tests for web/repository concerns,
- full integration only when cross-layer wiring matters.
Testing stack by layer
- Unit: JUnit 5 + Mockito.
- Controller slice:
@WebMvcTest + MockMvc.
- Persistence/integration:
@SpringBootTest or @DataJpaTest with in-memory DB.
- Optional: Testcontainers for infrastructure fidelity when in-memory DB is insufficient.
Persistence tests
Applies to repository/integration-style tests.
- Use transactional rollback per test class (
@Transactional + @Rollback) to avoid side effects.
- Seed stable data via SQL scripts when needed (
src/test/resources/sql/ + @Sql).
- After write operations (
create/update/delete), call EntityManager.flush() before assertions.
- Verify DB state independently from ORM behavior whenever possible:
JdbcTestUtils.countRowsInTable
JdbcTestUtils.countRowsInTableWhere
- Keep shared constants and entity factories in a central
InstanceProvider.
- Prefer fixed IDs/emails/names in test constants that match SQL seeds.
- File naming:
<Entity>RepositoryTest.
Persistence example
@Transactional
@Rollback
@SpringBootTest
class UserRepositoryTest {
private static final String EMAIL = "test@example.com";
@PersistenceContext
private EntityManager em;
@Autowired
private UserRepository userRepository;
@Autowired
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
@BeforeEach
void setUp() {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Test
void testCreate() {
int before = JdbcTestUtils.countRowsInTable(jdbcTemplate, "users");
User user = userRepository.create(EMAIL, "secret", "John", "Doe");
em.flush();
assertEquals(before + 1, JdbcTestUtils.countRowsInTable(jdbcTemplate, "users"));
assertNotNull(user);
}
}
Service tests
Pure unit tests (no Spring context).
- Use Mockito JUnit integration (
@ExtendWith(MockitoExtension.class)).
- Mock collaborators with
@Mock.
- Build subject with
@InjectMocks.
- Stub only what the scenario needs.
- Use
assertThrows for failure scenarios.
- File naming:
<Service>ImplTest.
Service example
@ExtendWith(MockitoExtension.class)
class UserServiceImplTest {
private static final long USER_ID = 1L;
@InjectMocks
private UserServiceImpl userService;
@Mock
private UserRepository userRepository;
@Test
void testFindByIdExistingUser() {
when(userRepository.findById(USER_ID)).thenReturn(Optional.of(new User()));
Optional<User> result = userService.findById(USER_ID);
assertTrue(result.isPresent());
}
@Test
void testFindByIdNonExisting() {
when(userRepository.findById(anyLong())).thenReturn(Optional.empty());
Optional<User> result = userService.findById(1L);
assertFalse(result.isPresent());
}
}
Controller tests
Use Mockito helpers or slice tests based on scope.
- For request logic/helpers, prefer Mockito unit tests.
- For endpoint contract and MVC behavior, use
@WebMvcTest + MockMvc.
- Mock auth/request objects as needed.
- If entity IDs are generated and lack setters, use local test helpers (reflection-based if required).
- File naming:
<Entity>ControllerTest.
Controller helper pattern
private User createUserWithId(String email, Long id) throws Exception {
User user = new User(email);
Field idField = User.class.getDeclaredField("id");
idField.setAccessible(true);
idField.set(user, id);
return user;
}
Keep small helper methods (createUserWithId, createMockAuthentication, etc.) inside the test class to reduce
duplication and improve readability.
Test review checklist