我有一个服务类,我需要对它进行单元测试。这个服务有一个upload方法,它会调用其他更新数据库的服务(autowired bean)。我需要模拟其中的一些服务,还有一些服务可以按原样执行。
@Service
public class UploadServiceImpl implements UploadService{
@Autowired
private ServiceA serviceA;
@Autowired
private ServiceB serviceB;
public void upload(){
serviceA.execute();
serviceB.execute():
//code...
}
在上面的例子中,我需要模拟ServiceA,但是我希望ServiceB按原样运行并执行它的功能。我的Junit测试如下所示:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Swagger2SpringBoot.class)
public class UploadServiceTest {
@Mock
private ServiceA serviceA;
@InjectMocks
private UploadServiceImpl uploadService;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testUpload(){
uploadService.upload();
}
当我执行这个命令时,我在UploadServiceImpl
中得到serviceB.execute();
处的NPE。
有什么问题吗?
**注意:**我没有指定被模拟对象的行为,因为我并不真正关心,而且被模拟对象的默认行为是什么也不做。
谢谢你!
7条答案
按热度按时间f8rj6qna1#
通常在单元测试时,你想要模拟一个类的所有外部依赖项,这样单元测试就可以保持独立,并且专注于被测试的类。
然而,如果您想混合Spring自动化和Mockito模拟,一个简单的解决方案是同时使用
@InjectMocks
和@Autowired
进行注解:这样做的实际效果是,首先Spring将自动连接bean,然后Mockito将立即用可用的模拟覆盖模拟的依赖项。
t5fffqht2#
您面临的问题是由于使用了
@InjectMocks
注解。@InjectMocks
标记了应执行注入的字段。Mockito将尝试仅通过构造函数注入、setter注入或属性注入来注入模拟-按此顺序。如果任何给定的注入策略失败,Mockito将不会报告失败。因此,在您的情况下,当尝试注入模拟时,只有一个模拟bean存在,而另一个beanServiceA没有被注入。
您可以尝试完全不使用
@InjectMocks
,而是为您要模拟的方法传递一个模拟对象,同时将其余自动连接的对象传递到构造函数中。示例:在这里,为了测试,我传递了一个模拟对象和一个自动连接对象。
或者,另一种方法是将
@Autowired
注解与@InjectMocks.@Autowired @InjectMocks
沿着使用,它将注入模拟的类,而自动连接的注解添加该类可能具有的任何其他依赖项。答案来自:https://medium.com/@vatsalsinghal/autowired-and-injectmocks-in-tandem-a424517fdd29
x6492ojm3#
新增
以创建可注入缺失服务的模拟,就像对服务A所做的那样。
wd2eg0qa4#
在我的例子中,除了使用@InjectMocks和@Autowired的组合之外,我还必须为被测试类中的模拟对象提供setter(在原始示例中,为UploadServiceImpl中的ServiceA提供setter)。
gorkyyrv5#
另一种方法是定义一个自动连接的构造函数,以便您可以正确地测试服务。
qncylg1j6#
在我看来,我们正在编写单元测试用例,我们不应该为了测试一段代码而初始化Spring上下文。
所以,
我使用Mockito来模拟我的主目标测试类中的
Autowired
bean,并将这些模拟bean注入到我的主测试类Object中可能听起来令人困惑,请参见以下示例💥
我使用的依赖项
我的主要类是数学和计算器bean是自动连接的
测试类
现在,
cal
在Maths类中将不为空,并将按预期工作kg7wmglp7#
如果不使用ReflectionTestUtils,我就无法让它工作。如果可行的话,设置构造函数是一个选项。