集成测试
SpringBootTest 集成测试
利用
因为我们拥有完整的应用程序上下文,包括
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
class RegisterUseCaseIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private UserRepository userRepository;
@Test
void registrationWorksThroughAllLayers() throws Exception {
UserResource user = new UserResource("Zaphod", "zaphod@galaxy.net");
mockMvc
.perform(
post("/forums/{forumId}/register", 42L)
.contentType("application/json")
.param("sendWelcomeMail", "true")
.content(objectMapper.writeValueAsString(user))
)
.andExpect(status().isOk());
UserEntity userEntity = userRepository.findByName("Zaphod");
assertThat(userEntity.getEmail()).isEqualTo("zaphod@galaxy.net");
}
}
自定义Application Context
一个相对完善的集成测试用例如下:
@SpringBootTest(
SpringBootTest.WebEnvironment.MOCK,
classes = Application.class)
@AutoConfigureMockMvc
@TestPropertySource(
locations = "classpath:application-integrationtest.properties")
public class EmployeeRestControllerIntegrationTest {
@Autowired
private MockMvc mvc;
@Autowired
private EmployeeRepository repository;
// write test cases here
}
我们可以使用
spring.datasource.url = jdbc:h2:mem:test
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
如果要针对
自定义属性
通常,在测试中,有必要将一些配置属性设置为与生产设置中的值不同的值:
@SpringBootTest(properties = "foo=bar")
class SpringBootPropertiesTest {
@Value("${foo}")
String foo;
@Test
void test() {
assertThat(foo).isEqualTo("bar");
}
}
如果我们的许多测试需要相同的属性集,则可以创建配置文件 application-<profile>.properties
或application-<profile>.yml
,并通过激活某个配置文件从该文件中加载属性:
// # application-test.yml
// foo: bar
@SpringBootTest
@ActiveProfiles("test")
class SpringBootProfileTest {
@Value("${foo}")
String foo;
@Test
void test() {
assertThat(foo).isEqualTo("bar");
}
}
自定义整套属性的另一种方法是使用
// # src/test/resources/foo.properties
// foo=bar
@SpringBootTest
@TestPropertySource(locations = "/foo.properties")
class SpringBootPropertySourceTest {
@Value("${foo}")
String foo;
@Test
void test() {
assertThat(foo).isEqualTo("bar");
}
}
自定义Bean
如果我们只想测试应用程序的某个部分而不是测试从传入请求到数据库的整个路径,则可以使用
@SpringBootTest
class MockBeanTest {
@MockBean
private UserRepository userRepository;
@Autowired
private RegisterUseCase registerUseCase;
@Test
void testRegister() {
// given
User user = new User("Zaphod", "zaphod@galaxy.net");
boolean sendWelcomeMail = true;
given(userRepository.save(any(UserEntity.class)))
.willReturn(userEntity(1L));
// when
Long userId = registerUseCase.registerUser(user, sendWelcomeMail);
// then
assertThat(userId).isEqualTo(1L);
}
}
在这种情况下,我们用模拟代替了
package other.namespace;
@Component
public class Foo {}
@SpringBootTest
@Import(other.namespace.Foo.class)
class SpringBootImportTest {
@Autowired
Foo foo;
@Test
void test() {
assertThat(foo).isNotNull();
}
}
默认情况下,
自定义SpringBootApplication
我们甚至可以创建一个完整的自定义
@SpringBootTest(classes = CustomApplication.class)
class CustomApplicationTest {}
但是在执行此操作时,我们正在测试可能与生产环境完全不同的应用程序上下文,这种做法反而不值得推荐,我们更应该去以条件方式控制某个
@Configuration
@EnableScheduling
@ConditionalOnProperty(
name = "wx.scheduling.enabled",
havingValue = "true",
matchIfMissing = true
)
public class SchedulingConfiguration {}
@SpringBootTest(properties = "wx.scheduling.enabled=false")
class SchedulingTest {
@Autowired(required = false)
private SchedulingConfiguration schedulingConfiguration;
@Test
void test() {
assertThat(schedulingConfiguration).isNull();
}
}
数据库的集成测试
Mybatis 内存测试
我们还是建议尽可能地使用内存数据库进行测试,以下就是使用
@ExtendWith(SpringExtension.class)
@SpringBootTest(
classes = { ApplicationTunnelTest.TestConfig.class, ApplicationTunnel.class }
)
class ApplicationTunnelTest {
@Autowired
private ApplicationTunnel applicationTunnel;
@Test
void testList() {
Assertions.assertNotEquals(0, applicationTunnel.list().size());
}
@Configuration
@MapperScan(basePackageClasses = { ApplicationMapper.class })
@EnableTransactionManagement
public static class TestConfig extends AbstractHsqlMyBatisDbConfig {
@Override
protected void configDataSourceBuilder(EmbeddedDatabaseBuilder builder) {
builder
.setName("admin_wx_application")
.addScript("classpath:db/schema/hsql/create_admin_schema.sql")
.addScript("classpath:db/data/common/create_admin_system_data.sql")
.addScript("classpath:db/data/common/create_admin_test_data.sql");
}
}
}