在我工作的项目中,我们已经通过以下方式初始化单元测试服务:
类似这样的东西:
@RunWith(SpringRunner.class)
public class ServiceTest extends AbstractUnitTest {
@Mock private Repository repository;
private Service service;
@Before
public void init() {
service = new Service(repository);
when(repository.findById(any(Long.class))).thenReturn(Optional.of(new Entity()));
}
}
但是我们的新开发人员建议使用@Autowired
和@SpringBootTest
@SpringBootTest(classes = ServiceTest.class)
@MockBean(classes = Repository.class)
@RunWith(SpringRunner.class)
public class ServiceTest extends AbstractUnitTest {
@MockBean private Repository repository;
@Autowired private Service service;
@Before
public void init() {
when(repository.findById(any(Long.class))).thenReturn(Optional.of(new Entity()));
}
}
在此之前,我认为@Autowired
和@SpringBootTest
仅应在集成测试中使用。但是用Google搜索很多,我发现有人在单元测试中使用了这两个。
我读了boot-features-testing。另外,我阅读了此Unit tests vs integration tests with Spring。
对我来说,我们仍然需要让Spring参与单元测试的依赖注入,因为我们可以自己完成单元测试。
因此,应该在单元测试中使用@Autowired
和@SpringBootTest
吗?
答案 0 :(得分:3)
不。 unit 测试用于隔离测试单个组件。在bean中使用构造函数注入使您可以非常简单地调用new SomeService(myMock)
,而无需Spring。
编写 component 或 functional 测试(测试您的应用程序,但不将其连接到外部服务以进行完整的集成测试,仅模拟外部接口;这对事情有好处像MockMvc测试)非常适合@SpringBootTest
,在这种情况下,您可能需要在Spring配置中创建模拟对象并将其自动连接到测试中,以便您进行操作。
答案 1 :(得分:0)
在TDD中进行测试应该是有帮助的,直接的,快速的,并保持最少的维护。否则,开发人员会感到烦恼,并尝试避免进行测试。
因此,我建议不要严格要求它是纯单元测试还是有点集成。选择最适合您的情况的测试范围,并使用适合此范围的技术功能。
如果您要进行“真实的”单元测试,请自己使用一个独立的方法,请不要使用DI。如果该方法做了有意义的事情,例如算法,计算,决策。在这里模拟数据源非常有用,以获得可预测的输入值。 您真正不需要的@SpringBootTest的缺点是启动时非常麻烦(取决于项目大小),这真令人讨厌。
如果方法调用依赖项上的功能,请使用CDI。 1)手动设置myService.service2 = new Service2()
会给您留下同样不是由DI-Container处理的Service2,这可能需要您设置更多的依赖项... 2)Spring中的CDI测试很容易-那么为什么您会使用设置代码来夸大您的测试吗? 3)DI涉及的代理有时与简单实例的行为有所不同。
与@SpringBootTest相比,使用@ContextConfiguration(classes = {ServiceTest.class})
可以更快地启动CDI。
请勿使用单元测试来测试粘合代码,因为它没有任何内在价值。这些测试很难理解(谁喜欢记录测试?),将需要大量模拟,并且经常会发生变化。与其他方法/类一起测试此类代码,即使这意味着您仅对代码的这些部分进行集成测试。