Our current test suite heavily use integration tests using @SpringBootTest, which makes tests slow, brittle, and harder to maintain. We need to refactor the entire test suite to prioritize pure unit tests (95%) over integration tests (5%) and ensure we only test the code that actually exists in our application.
-
Maximize unit test coverage - Replace most @SpringBootTest tests with lightweight @ExtendWith(MockitoExtension.class) tests
Test only production code - No testing of Spring framework, third-party libraries, or non-existent behaviors
Improve test speed - Unit tests should execute in < 100ms each
Increase maintainability - Clear, focused tests that are easy to understand and modify
-
Unit Tests First (95% of all tests)
Characteristics of a proper unit test:
Tests ONE class in isolation
Uses @ExtendWith(MockitoExtension.class) (NOT @SpringBootTest)
Mocks ALL dependencies with @mock and @Injectmocks
No database, no Spring context, no MockMvc
Executes in < 100ms
Example structure:
@ExtendWith(MockitoExtension.class)
class ServiceNameUnitTest {
@Mock
private DependencyService dependencyService;
@Mock
private Repository repository;
@InjectMocks
private ServiceName serviceUnderTest;
@Test
void shouldReturnExpectedResultWhenValidInput() {
// Arrange
InputData input = new InputData("value");
when(dependencyService.process(any())).thenReturn(expectedData);
// Act
Result result = serviceUnderTest.methodToTest(input);
// Assert
assertThat(result).isNotNull()
.extracting("field")
.isEqualTo(expectedValue);
verify(dependencyService).process(any());
}
}
-
Integration Tests (5% maximum)
Only use when:
Testing critical cross-component interactions
Testing custom repository queries
End-to-end controller testing (use @WebMvcTest when possible, not @SpringBootTest)
-
Test Only What Exists
To do:
Analyze the production class before writing tests
Test each public method
Cover conditional branches (if/else, switch)
Test error cases (exceptions, validations)
Test edge cases and boundary conditions
Not to do:
Test unimplemented behaviors
Test methods from other microservices/libraries
Test Spring infrastructure (dependency injection, transactions)
Test frameworks (JPA, Jackson, Spring MVC)
Test multiple classes together in unit tests
Test private methods directly
Our current test suite heavily use integration tests using @SpringBootTest, which makes tests slow, brittle, and harder to maintain. We need to refactor the entire test suite to prioritize pure unit tests (95%) over integration tests (5%) and ensure we only test the code that actually exists in our application.
Maximize unit test coverage - Replace most @SpringBootTest tests with lightweight @ExtendWith(MockitoExtension.class) tests
Test only production code - No testing of Spring framework, third-party libraries, or non-existent behaviors
Improve test speed - Unit tests should execute in < 100ms each
Increase maintainability - Clear, focused tests that are easy to understand and modify
Unit Tests First (95% of all tests)
Characteristics of a proper unit test:
Tests ONE class in isolation
Uses @ExtendWith(MockitoExtension.class) (NOT @SpringBootTest)
Mocks ALL dependencies with @mock and @Injectmocks
No database, no Spring context, no MockMvc
Executes in < 100ms
Example structure:
Integration Tests (5% maximum)
Only use when:
Testing critical cross-component interactions
Testing custom repository queries
End-to-end controller testing (use @WebMvcTest when possible, not @SpringBootTest)
Test Only What Exists
To do:
Analyze the production class before writing tests
Test each public method
Cover conditional branches (if/else, switch)
Test error cases (exceptions, validations)
Test edge cases and boundary conditions
Not to do:
Test unimplemented behaviors
Test methods from other microservices/libraries
Test Spring infrastructure (dependency injection, transactions)
Test frameworks (JPA, Jackson, Spring MVC)
Test multiple classes together in unit tests
Test private methods directly