SuperAPI AI Directory

unit-testing

Testing & quality

View repository

Updated 10-15 23:58

About this skill

Unit Testing Skill Pack

A professional guide to writing high-quality unit tests, based on the JUnit 5 and Mockito frameworks.

Testing Principles

  1. Test Independence: Each test case should run independently, without depending on the execution order or results of other tests
  2. Single Responsibility: Each test verifies only one specific behavior or scenario
  3. Clear Naming: Test method names should clearly describe the test scenario; recommended format:方法名_测试场景_期望结果
  4. Comprehensive Coverage: Includes three dimensions: normal scenarios, boundary conditions, and exceptional situations

Test Structure (AAA Pattern)

Each test case should follow the Arrange-Act-Assert three-part structure:

@Test
void calculateTotal_withValidItems_returnsCorrectSum() {
    // Arrange - 准备测试数据和依赖
    List<Item> items = Arrays.asList(
        new Item("A", 10.0),
        new Item("B", 20.0)
    );
    Calculator calculator = new Calculator();
    
    // Act - 执行被测试的方法
    double result = calculator.calculateTotal(items);
    
    // Assert - 验证结果是否符合期望
    assertEquals(30.0, result, 0.001);
}

Common Assertions

JUnit 5 Assertions

  • assertEquals(expected, actual) - Verify equality
  • assertNotNull(actual) - Verify not null
  • assertTrue(condition) / assertFalse(condition) - Verify boolean conditions
  • assertThrows(Exception.class, () -> {...}) - Verify exception thrown
  • assertAll() - Batch assertions, all executed
  • assertTimeout(duration, () -> {...}) - Verify execution time

AssertJ Fluent Assertions (Recommended)

assertThat(result)
    .isNotNull()
    .isInstanceOf(User.class)
    .extracting(User::getName)
    .isEqualTo("张三");

Mock Usage Guide

Basic Mock

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    void getUser_whenExists_returnsUser() {
        // 定义Mock行为
        when(userRepository.findById(1L))
            .thenReturn(Optional.of(new User("张三")));
        
        // 执行测试
        User user = userService.getUser(1L);
        
        // 验证结果
        assertEquals("张三", user.getName());
        
        // 验证方法调用
        verify(userRepository).findById(1L);
    }
}

Mock Precautions

  • Use@Mockannotation to mark dependencies
  • Use@InjectMocksto automatically inject Mock objects
  • Usewhen().thenReturn()to define Mock return values
  • Useverify()to verify whether a method was called
  • Useany()、eq()and other matchers to flexibly match parameters

Boundary Condition Testing Checklist

Boundary conditions that must be tested:

  • Null value (null): The case where an input parameter is null
  • Empty collection: Empty list, empty Map, empty string
  • Single-element collection: A collection with only one element
  • Large amount of data: Performance and correctness in large data volume scenarios
  • Boundary values: Maximum value, minimum value, 0, -1, etc.
  • Special characters: Spaces, newline characters, special symbols
  • Concurrent scenarios: Multi-threaded concurrent access

Test Coverage Strategy

Method-level Coverage

Each public method should include at least the following tests:

  • Normal case tests
  • Exception case tests (invalid parameters, abnormal state, etc.)
  • Boundary condition tests

Branch Coverage

  • Every branch of if/else should be covered by tests
  • Every case of switch/case should be tested
  • Boundary conditions of loops (0 times, 1 time, multiple times)

Best Practices

  1. Test First: Adopt TDD (Test-Driven Development) when possible
  2. Fast Execution: Unit tests should execute quickly and avoid depending on external resources
  3. Repeatable: Test results should be stable and repeatable, not dependent on the execution environment
  4. Automation: Integrate into the CI/CD process for automatic execution
  5. Regular Refactoring: Test code also needs refactoring and maintenance

Anti-patterns (Avoid)

❌ Testing private methods (should test public interfaces) ❌ Testing third-party libraries (should be mocked out) ❌ Testing getters/setters (unnecessary) ❌ Over-mocking (leads to fragile tests) ❌ Ignoring exception testing