FIRST Properties of Good Tests
following problems with your tests:
• Tests that make little sense to someone following them
• Tests that fail sporadically
• “Tests” that don’t prove anything worthwhile
• Tests that require a long time to execute
• Tests that don’t sufficiently cover the code
• Tests that couple too tightly to implementation, meaning that small changes break lots of tests all at once
• Convoluted tests that jump through numerous setup hoops
Types of Testing
Spring Boot applications can be tested at various levels, including:
- Unit Testing: Testing individual components, such as classes or methods, in isolation.
- Integration Testing: Verifying that different components or services work correctly together.
- Functional Testing: Testing the application’s functionality from the user’s perspective.
- End-to-End Testing: Testing the entire application, including its external dependencies, in a production-like environment.
Unit Test
单元测试是测试驱动开发 (TDD) 的基础。在 TDD 中,首先编写失败的测试,然后编写代码以满足测试,然后通过重构代码和应用模式来提高代码质量。所以单元测试驱动设计。他们减少了工程,因为代码只编写以满足失败的测试。自动化测试为重构和新功能提供了快速的回归安全网络。
Spring Test - Integration Testing
Leverage Spring Boot’s Testing Annotations
- Use
@SpringBootTest
to load the entire Spring context.
@SpringBootTest
@AutoConfigureMockMvc
class TestingWebApplicationTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
-
Use
MockMvc
to simulate HTTP requests and test the response from your controller. Use@AutoConfigureMockMvc
to automatically configureMockMvc
-
Use
@MockBean
to replace a real bean with a mock implementation.@Mock
vs@MockBean
:@Mock
is used for unit testing and mocking objects outside of the Spring context, while@MockBean
is used for Spring Boot integration testing to replace real beans with mock or spy versions within the Spring application context. -
当使用spy时,考虑使用
doReturn|Answer|Throw()
,spy默认所有方法均真实调用与使用
@MockBean
不同,上节中调用doReturn("").when(testService).doSomething()
时doSomething
方法被打桩。而when(testService.doSomething()).thenReturn("")
则达不到此效果。原因是:使用@SpyBean
修饰的testService
是一个真实对象,所以testService.doSomething()
会被真实调用。spy修饰的变量,Mockito会重新创建一个实例的copy,并不直接作用于真实实例
为测试主体类部分打桩考虑使用
SpyBean
, 为外部依赖打桩,考虑使用MockBean
。 -
Use
@DataJpaTest
to test repositories with an embedded database. -
Use @AutoConfigureTestDatabase to configure the test database.
-
Use @BeforeEach and @AfterEach to set up and tear down test fixtures. ``` @BeforeEach public void setUp() { // Initialize the EmployeeService or set up resources if needed employeeService = new EmployeeService();
}
@AfterEach public void tearDown() { // Clean up resources or perform other cleanup tasks employeeService = null; }
## Test Configuration
1. Use @TestConfiguration to provide additional beans for testing.
i. Create a static inner class in the same test class where we want to autowire the bean.
ii. Create a separate test configuration class and import it using the @Import annotation.
2. Use @ConfigurationProperties to inject properties from a configuration file.
3. Use @ActiveProfiles to activate a specific profile for testing when you have multiple profiles.
4. Use @DynamicPropertySource to set dynamic configuration properties for tests.
5. Use @DirtiesContext to reset the Spring context after a test.
1. @DirtiesContext通常用于测试方法对Spring应用程序上下文有副作用,不能通过常规事务或回滚机制撤消的情况。
2. 就性能而言,重置应用程序上下文的代价相对较高,因此要谨慎使用。
6. Use RestTemplate to make HTTP requests.
7. Use @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) to start the server on a random port. Use TestRestTemplate to make HTTP requests and assert responses.
8. Use @Sql to execute SQL scripts before and after a test.
9. Use @Disabled to disable a test temporarily.
10. Use @RepeatedTest to repeat a test a specified number of times.
# Testing Frameworks
There are several testing tools commonly used in Spring Boot applications, including:
- JUnit: A widely-used testing framework for Java.
- Mockito: A mocking framework for creating mock objects in tests.
- Testcontainers: Provides lightweight, throwaway instances of common databases or services for testing.
- Spring Boot Test: Offers annotations and utilities for testing Spring Boot applications.
- RestAssured: A Java DSL for simplifying the testing of REST services.
- Selenium: Used for web application testing, especially end-to-end testing.
- Jacoco: A code coverage analysis tool that helps you identify areas of your codebase that need more testing.
- WireMock: A tool for mocking HTTP services, useful for testing external service interactions.
## 并发测试
#是否允许并行执行true/false junit.jupiter.execution.parallel.enabled=true #是否支持方法级别多线程same_thread/concurrent junit.jupiter.execution.parallel.mode.default=concurrent #是否支持类级别多线程same_thread/concurrent junit.jupiter.execution.parallel.mode.classes.default=concurrent
the maximum pool size can be configured using a ParallelExecutionConfigurationStrategy
junit.jupiter.execution.parallel.config.strategy=fixed junit.jupiter.execution.parallel.config.fixed.parallelism=5
## 参数化测试
```java
@ParameterizedTest(name = "{0} is expected to output {1}")
@MethodSource("fizzBuzzTestCases")
public void fizzBuzz(int input, string expected) {
assertEquals(expected, underTest.fizzBuzz(input));
}
private static Stream<Arguments> fizzBuzzTestCases() {
return Stream.of(
Arguments.of(named.of(1, "1 - not divisible by 3 or 5"), "1"),
Arguments.of(named.of(2, "2 - not divisible by 3 or 5"), "2"),
Arguments.of(named.of(3, "3 - divisible by 3"), "Fizz"),
Arguments.of(named.of(4, "4 - not divisible by 3 or 5"), "4"),
Arguments.of(named.of(5, "5 - divisible by 5"), "Buzz"),
Arguments.of(named.of(6, "6 - divisible by 3"), "Fizz"),
Arguments.of(named.of(10, "10 - divisible by 5"), "Buzz"),
Arguments.of(named.of(11, "11 - not divisible by 3 or 5"), "11"),
Arguments.of(named.of(15, "15 - divisible by both 3 and 5"), "FizzBuzz")
);
}