TestMethodCodeStyle
Plan
- Test Class Creation: Create a dedicated test class for the target class or method.
- JUnit 5 Annotations: Use JUnit 5 annotations (e.g.,
@Test, @Nested, @DisplayName) to structure the tests.
- Scenario-Based Testing: Write tests for each scenario based on the original method's logic. Ensure that all possible scenarios are covered.
- Mocking Dependencies: Use mocking frameworks (e.g., Mockito) to mock dependencies where necessary.
- Referencing Classes:
- Identify all classes and methods that the target method depends on.
- Ensure that these dependencies are either mocked or properly instantiated in the test setup.
- If the dependency is complex, provide a simplified implementation or mock behavior to isolate the method under test.
- Test Structure:
- Create one test method per scenario.
- Use a nested class to group all scenarios for a single method.
- If the method is tested using
assertThrows, include additional assertions to verify the exception's message or properties.
- Code Style: Follow the provided code style for test structure.
- Parameterization: Use
@ParameterizedTest and @CsvSource or @MethodSource for tests with multiple input-output combinations to reduce redundancy.
Example Code
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class DemoTest {
@Nested
@DisplayName("Tests for demoMethod")
class DemoMethodTests {
@Test
@DisplayName("Scenario 1: When input is valid, then return expected result")
void whenInputIsValid_thenReturnExpectedResult() {
// Arrange
MyService myService = mock(MyService.class);
String input = "valid-input";
String expectedOutput = "expected-output";
when(myService.process(input)).thenReturn(expectedOutput);
// Act
String result = myService.process(input);
// Assert
assertEquals(expectedOutput, result);
}
@Test
@DisplayName("Scenario 2: When input is invalid, then throw IllegalArgumentException")
void whenInputIsInvalid_thenThrowIllegalArgumentException() {
// Arrange
MyService myService = mock(MyService.class);
String invalidInput = "invalid-input";
when(myService.process(invalidInput)).thenThrow(new IllegalArgumentException("Invalid input"));
// Act & Assert
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
myService.process(invalidInput);
});
assertEquals("Invalid input", exception.getMessage());
}
@ParameterizedTest
@CsvSource({
"input1, output1",
"input2, output2",
"input3, output3"
})
@DisplayName("Scenario 3: Parameterized test for multiple input-output combinations")
void parameterizedTest(String input, String expectedOutput) {
// Arrange
MyService myService = mock(MyService.class);
when(myService.process(input)).thenReturn(expectedOutput);
// Act
String result = myService.process(input);
// Assert
assertEquals(expectedOutput, result);
}
}
}