Skip to main content

unit-testing-patterns

Implement JUnit 5, Mockito, and AssertJ patterns with 80%+ code coverage for CIA platform unit tests

소스 정보

저장소
Hack23/cia
최근 소스 활동
2026년 2월 1일 00:05
감지된 SKILL.md 언어
영어
스타
239
포크
57

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
unit-testing-patterns
description
Implement JUnit 5, Mockito, and AssertJ patterns with 80%+ code coverage for CIA platform unit tests
license
Apache-2.0
# Unit Testing Patterns Skill ## Purpose Write effective, maintainable unit tests using JUnit 5, Mockito, and AssertJ that achieve 80%+ code coverage. ## When to Use - ✅ Testing business logic in services - ✅ Testing data validation - ✅ Testing utility functions - ✅ Test-driven development (TDD) ## JUnit 5 Patterns ### Test Structure (AAA Pattern) ```java @ExtendWith(MockitoExtension.class) class PoliticianServiceTest { @Mock private PoliticianRepository repository; @Mock private AuditLogger auditLogger; @InjectMocks private PoliticianService service; @Test @DisplayName("Should find politician by ID when exists") void shouldFindPoliticianById() { // Arrange String politicianId = "196401011234"; Politician expected = new Politician(politicianId, "John", "Doe"); when(repository.findById(politicianId)).thenReturn(Optional.of(expected)); // Act Politician actual = service.findById(politicianId); // Assert assertThat(actual).isNotNull(); assertThat(actual.getId()).isEqualTo(politicianId); assertThat(actual.getFirstName()).isEqualTo("John"); } @Test @DisplayName("Should throw exception when politician not found") void shouldThrowExceptionWhenNotFound() { // Arrange String politicianId = "999999999999"; when(repository.findById(politicianId)).thenReturn(Optional.empty()); // Act & Assert assertThatThrownBy(() -> service.findById(politicianId)) .isInstanceOf(ResourceNotFoundException.class) .hasMessageContaining("Politician not found"); } } ``` ### Parameterized Tests ```java @ParameterizedTest @CsvSource({ "196401011234, true", "999999999999, true", "12345, false", "abcdefghijkl, false", "'', false" }) @DisplayName("Should validate Swedish personal ID format") void shouldValidatePersonalIdFormat(String personalId, boolean expected) { assertThat(validator.isValidPersonalId(personalId)).isEqualTo(expected); } @ParameterizedTest @ValueSource(strings = {"password", "12345678", "qwerty", "admin"}) @DisplayName("Should reject common passwords") void shouldRejectCommonPasswords(String password) { assertThat(passwordValidator.isWeak(password)).isTrue(); } ``` ### Test Lifecycle ```java class DatabaseTest { @BeforeAll static void setupClass() { // Run once before all tests initializeTestDatabase(); } @BeforeEach void setup() { // Run before each test clearDatabase(); } @AfterEach void teardown() { // Run after each test rollbackTransaction(); } @AfterAll static void teardownClass() { // Run once after all tests closeConnections(); } } ``` ## Mockito Best Practices ### Stubbing ```java @Test void shouldReturnCachedData() { // Stub method to return specific value when(cache.get("key")).thenReturn("value"); // Stub with argument matchers when(repository.findByName(anyString())).thenReturn(new ArrayList<>()); // Stub with custom answer when(service.process(any())).thenAnswer(invocation -> { String arg = invocation.getArgument(0); return arg.toUpperCase(); }); // Stub to throw exception when(repository.findById("invalid")) .thenThrow(new IllegalArgumentException("Invalid ID")); } ``` ### Verification ```java @Test void shouldLogAuditEvent() { // Arrange Politician politician = new Politician("123", "John", "Doe"); // Act service.create(politician); // Verify method was called once verify(auditLogger).log(eq("CREATE_POLITICIAN"), any(Politician.class)); // Verify exact number of calls verify(repository, times(1)).save(politician); // Verify never called verify(emailService, never()).sendNotification(any()); // Verify no more interactions verifyNoMoreInteractions(auditLogger); } ``` ### Argument Captors ```java @Test void shouldSaveWithCorrectTimestamp() { ArgumentCaptor<Politician> captor = ArgumentCaptor.forClass(Politician.class); service.create(new Politician("123", "John", "Doe")); verify(repository).save(captor.capture()); Politician saved = captor.getValue(); assertThat(saved.getCreatedAt()).isCloseTo( LocalDateTime.now(), within(1, ChronoUnit.SECONDS) ); } ``` ## AssertJ Fluent Assertions ```java @Test void shouldHaveCorrectProperties() { Politician politician = service.findById("123"); // Fluent assertions assertThat(politician) .isNotNull() .hasFieldOrPropertyWithValue("firstName", "John") .hasFieldOrProperty("lastName") .extracting("party") .isEqualTo("S"); // Collection assertions List<Politician> politicians = service.findAll(); assertThat(politicians) .isNotEmpty() .hasSize(5) .extracting("firstName") .contains("John", "Jane") .doesNotContain("Invalid"); // Exception assertions assertThatThrownBy(() -> service.delete("invalid")) .isInstanceOf(NotFoundException.class) .hasMessage("Politician not found") .hasNoCause(); } ``` ## Code Coverage ### Target: 80% Line Coverage, 70% Branch Coverage ```xml <!-- pom.xml --> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco.version}</version> <executions> <execution> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>report</id> <phase>test</phase> <goals> <goal>report</goal> </goals> </execution> <execution> <id>check</id> <goals> <goal>check</goal> </goals> <configuration> <rules> <rule> <element>BUNDLE</element> <limits> <limit> <counter>LINE</counter> <value>COVEREDRATIO</value> <minimum>0.80</minimum> </limit> <limit> <counter>BRANCH</counter> <value>COVEREDRATIO</value> <minimum>0.70</minimum> </limit> </limits> </rule> </rules> </configuration> </execution> </executions> </plugin> ``` ## Test Organization ``` src/test/java/ └── com/hack23/cia/ ├── service/ │ ├── impl/ │ │ ├── PoliticianServiceTest.java │ │ └── VotingAnalysisServiceTest.java │ └── api/ │ └── PoliticianServiceIT.java (Integration tests) ├── util/ │ ├── DateUtilsTest.java │ └── ValidationUtilsTest.java └── testfoundation/ ├── TestDataFactory.java └── AbstractServiceTest.java ``` ## References - JUnit 5: https://junit.org/junit5/ - Mockito: https://site.mockito.org/ - AssertJ: https://assertj.github.io/doc/ - UnitTestPlan.md
GitHub에서 보기