如何写测试 八

对于一般的开发人员来说,Spring是一个解决了很多问题,非常优秀的框架,其解决了Java服务器端开发过程中,需要进行的打包并部署到容器的操作。

而在Spring这个框架之中,一方面提供了开发上的简易,另一方面也提供了测试上的方便,无论是单元测试和集成测试都可以完美支持。

更加具体的,则可以体现在Spring提供的核心功能,也就是依赖注入,在实际开发之中,通常会使用依赖注入来完成相关组件的组装。对于Spring的测试,也是基于了依赖注入,只要是依赖注入的组件,Spring都可以很好的提供测试。

这里我们给出两个反例

比如使用不基于字段的注入

@Service

public class TodoItemService {

@Autowired

private TodoItemRepository repository;

}

这里我们通过字段的方式进行了注入,这种方式会让这个Service在项目启动的时候自动初始化并将仓库类进行注入。

其支持和Spring的集成测试,但是对于单元测试却不是很友好。这里我们如果是改为将Autowired注解放在构造函数上,让Spring去初始化

@Service

public class TodoItemService {

private final TodoItemRepository repository;

@Autowired

public TodoItemService(final TodoItemRepository repository) {

this.repository = repository;

}

}

这里我们就可以在单元测试的时候像一个普通对象进行测试了。

其次是不要依赖ApplicationContext

在某些工程之中,有些代码会尝试利用ApplicationContext中的静态方法getBean来获取到Spring容器池中的Bean对象。

但是这种代码的使用,是一种错误的做法,其打破了DI容器的原本设计,另一方面还让核心代码对第三方代码进行了依赖。

所以总结一下,对于Spring的使用应该在代码层面不依赖于Spring,而不是深深的依赖Spring。

而Spring对于测试,还提供了一些专属的注解

比如@MockBean,其就类似

@BeforeEach

public void setUp() {

this.repository = mock(TodoItemRepository.class);

}

但是其在集成测试的时候,会提供依赖注入的能力。

对于Spring提供的集成测试,我们则可以从两个角度来看,就是之前说过的数据库和Web角度。

对于数据库的角度,我们之前曾经给过一个例子

首先是我们可以使用@TestPropertySource来给出一个不同的配置,在里面声明不同配置。从而让我们无缝连接到不同的数据库。

再之后我们可以准备一个和未来线上数据库一致的测试数据库。这里并不推荐使用嵌入式的内存数据库,这是因为如果使用不同的数据库类型,可能会导致测试过程中出现sql或者函数无法应用的问题。

这里我们还是考虑使用一个相同版本的数据库,可以考虑准备一个配置更低的数据库。

然后之后利用@DataJpaTest,配置数据库回滚能力。

当然如果不是使用的JPA,而是其他的Mybatis等。则也有对应的注解。

比如Spring提供了@JdbcTest。则对应的是使用DataSource。

再之后是Web的测试,对于Spring也支持的很好

我们之前利用@SpringBootTest来将框架集成到了测试之中,做了集成测试

其也有一个简化版本@WebMvcTest

@WebMvcTest(TodoItemResource.class)

public class TodoItemResourceTest {

}

这样就就只集成TodoItemResource相关的部分了。

除此外,Spring还提供了模拟的Web访问

就是在SpringBootTest注解标记同时声明@AutoConfigureMockMvc,并在类中注入MockMvc对象即可。

@SpringBootTest

@AutoConfigureMockMvc

@Transactional

public class TodoItemResourceTest {

@Autowired

private MockMvc mockMvc;

@Test

public void should_add_item() throws Exception {

String todoItem = “{ ” +

“\”content\”: \”foo\”” +

“}”;

mockMvc.perform(MockMvcRequestBuilders.post(“/todo-items”)

.contentType(MediaType.APPLICATION_JSON)

.content(todoItem))

.andExpect(status().isCreated());

assertThat(repository.findAll()).anyMatch(item -> item.getContent().equals(“foo”));

}

}

这里的MockMvc并不是真的去进行了一次网络请求,而支持模拟请求去实际调用了代码,只不过调用链路上的各种Filter,拦截器都会被调用。

那么我们看了如何在Spring项目之中进行集成测试。主要是如何做数据库和Web接口的集成测试。

数据库我们说了如何集成不同的配置,以及配置数据回滚

Web测试则是模拟网络请求。进行相关的测试。

Spring的测试相关组件还有很多,还可以去查看其官方文档。

发表评论

邮箱地址不会被公开。 必填项已用*标注