>我正在测试一个"保存在数据库中"的公共方法,该方法还将一些保存的数据修改到服务。测试确保它正在保存它收到的内容,但发送不同的修改数据。当内部私有方法调用设置为自动连线的存储库时,问题就来了,其响应是 nullPointer 就像在反射中一样,自动连线的存储库未初始化。
因此,首先断言私有方法的答案,我对私有方法进行了反思。我用受控响应嘲笑内部自动连线服务,但没有发现如何设置模拟服务答案的结果。
我对测试仍然很陌生,所以我可能会犯一些错误,解释会尽力纠正它并进一步扩展该主题。
这适用于一个公共方法"X",它将某些内容保存在数据库中(返回保存内容的代码),然后执行其他一些操作,然后转到私有方法"Y"以验证某些数据,并在该私有方法中转到其他私有方法"Z",以创建一些新数据从另一个服务"B"和之前获取的数据中检索数据, 将其发送到外部服务"A"。所有这些都是在同一个类实现"classImpl"中完成的。私有方法"Z"接收与"X"方法相同的内容,它使用从"B"获得的数据生成并返回将在"A"服务中发送的数据。
@Test
@Rollback(false)
@Transactional(readOnly = false)
TEST{
testData testXData= new testData();
testXData.set()...
testXData.set()...
.......Generate data to be saved.
mockResponse controlledOutput = mock(mockResponse.class);
deliverInMockResponse deliverInMockResponse = new deliverInMockResponse();
deliverInMockResponse.set()...
deliverInMockResponse.set()...
.......Generate data to be delivered in the mockResponse.
when(controlledOutput.findByAnd(otherSomething)).thenReturn(deliverInMockResponse);
assertNotNull(testSaveMethodX(testXData));
String Something = "evalutaThis";
assertEquals(testXData.getSomething(),Something);
try{
classImpl publicImpl = new classImpl();
Method method = classImpl.class.getDeclaredMethod("Z", testData.class);
method.setAccessible(true);
methodZResponse Zoutput = (methodZResponse) method.invoke(publicImpl, testXData);
assertNotEquals(Zoutput.getSomething(),Something);
}
catch (Exception e){
assertNotNull(null);
}
}
至于私有方法模拟或测试,我宁愿建议你尝试 PowerMock 而不是自己编写反射。 这是一个很好的指南。还使用 PowerMockito 模拟私有方法
如果您在测试中运行自己制作的反射代码,那么测试的代码可能会做得更好。
并非所有代码都可以自动进行单元测试。为了能够测试代码,您应该以某种方式编写它。
您已在问题的代码片段中展示了测试,但您测试的代码在这里也非常重要。 从问题的第一段开始,我假设你有这样的东西:
class MyDao {
@Autowired
private SomeService service;
public void saveInDb() {
// do something with db
service.sendData();
}
}
由于在测试期间不会发生自动布线(因为在单元测试中,您没有 Spring 来发挥其魔力),因此很难测试saveInDb
方法
但是,此代码是有问题的,可以重构以获得更好的单元测试:
所以这里有一个提示:不要在字段上使用自动连线,而是使用构造函数注入重写代码:
class MyDao {
private SomeService service;
@Autowired // you can even omit this annotation in recent versions of spring
// spring will understand what should be injected if there is only one
// constructor in the class
public MyDao(SomeService service) {
this.service = service;
}
}
如果你觉得这是很多代码,你甚至可以使用 Lombok 项目为你生成一个构造函数,但这超出了问题的范围......
无论如何,您现在拥有一个具有明确定义的依赖项列表的类,必须在尝试创建此类实例的测试中指定该类。
单元测试在这里变得容易:
SomeService someService = Mockito.mock(SomeService.class);
MyDao underTest = new MyDao(someService);
与袁清飞之前给出的答案不同,我不建议使用PowerMock/PowerMockito之类的工具,只有在您无法更改测试的代码时才考虑使用这些工具(通常对于没有考虑测试的旧项目也是如此)