新建一个测试配置类 TestApplication
@Configuration @EnableAutoConfiguration
@ComponentScan(
excludeFilters = @ComponentScan.Filter(value = {
Application.class,
ApplicationChecker.class
}, type = FilterType.ASSIGNABLE_TYPE))
public class TestApplication {
// 配置测试使用内存数据库
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
}
新建一个测试公共类 CommonBeanIntegrationTest
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = TestApplication.class)
// 重新加载 Spring 上下文
// @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public abstract class CommonBeanIntegrationTest {
@After
public void emptyDatabases() {
// 清空数据库,运行速度相对于每次重新加载 Spring 上下文快很多
}
}正式开始写测试
- 常规测试类结构
public class UserTest extends CommonBeanIntegrationTest { @Autowired
private UserAccessor userAccessor; // 准备测试的 Bean
@Autowired
private UserRepository userRepository; // 测试中需要用到的辅助 Bean
@Before
public void setUp() {
// 每个测试开始前的操作
}
@Test
public void should_save_user_with_username() {
// given
String username = "foo";
// when
userAccessor.save(username);
// then
assertThat(userRepository.findOne(1).getUsername, is(username));
}
@After
public void tearDown() {
// 每个测试执行后的操作
}
}- 使用 Mock 时测试类结构
@RunWith(MockitoJUnitRunner.class) public class HttpClientTest {
@Mock
private ServerProperties serverProperties;
@InjectMocks // 把 @Mock 注解的对象注入到 httpClient 中
private HttpClient httpClient;
@Test
public void should_get_correct_port(){
when(serverProperties.getPort()).thenReturn(8080);
assertThat(httpClient.get(ApiUrl.list_node).getPort(), is(8080));
}
}- 混合使用前两种
public class UserTest extends CommonBeanIntegrationTest { @Autowired
private UserRepository userRepository;
@Mock
private HttpClient httpClient;
@Autowired
@InjectMocks
private UserAccessor userAccessor; // 准备测试的 Bean
@Before
public void setUp() {
MockitoAnnotations.initMocks(this); // 初始化并注入 @Mock 注解的对象
// 强制将 Mock 的 httpClient 对象注入 userAccessor 中
// ReflectionTestUtils.setField(userAccessor, "httpClient", httpClient);
}
@Test
public void test_something(){
// Test Code
}
}同时在需要测试的 Bean 上使用 @Autowired 和 @InjectMocks 注解后,可以达到只 Mock 需要 Mock 的对象,而其它对象依然是注入的真实对象的效果。
但是有时候可能会出现我们 Mock 的对象还是注入的真实对象的情况,此时可以使用 Spring Boot 提供的 ReflectionTestUtils 在 @Before 中强制手动设置需要 Mock 的对象的值。