Spring Boot Integration 测试

2016/2/1 posted in  Spring Boot comments
  1. 新建一个测试配置类 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();
    }
    }
  1. 新建一个测试公共类 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 上下文快很多
    }
    }
  2. 正式开始写测试

    • 常规测试类结构
    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 的对象的值。