Java 如何在下面的代码中模拟遗留对象?
我一直在使用mockito框架编写单元测试。 我有下面的遗留代码,如何在approvalAction方法中模拟RemoteService客户端对象而不重构它Java 如何在下面的代码中模拟遗留对象?,java,mockito,Java,Mockito,我一直在使用mockito框架编写单元测试。 我有下面的遗留代码,如何在approvalAction方法中模拟RemoteService客户端对象而不重构它 public Map<String, String> approvalAction(long documentId, ActionCommandDTO request, FormData formData, byte[] prevData) { RemoteService client = getRemoteServi
public Map<String, String> approvalAction(long documentId, ActionCommandDTO request, FormData formData, byte[] prevData) {
RemoteService client = getRemoteService();
String urlString = String.format("formExtensions/%s?%s", formData.getId(), getAuthParam(formData.getRealm()));
try {
response = client.postEntity(urlString, String.class, approvalSvcRequestStr);
} catch (Exception e) {
// TODO: handle rollback properly for P2P
handleApprovalActionFailed(documentId, request, formData, prevData);
}
return map;
}
private RemoteService getRemoteService() {
RemoteServiceConfig remoteServiceConfig = (RemoteServiceConfig) this.serviceConfigRegistry.getServiceConfigs().get("approval");
remoteServiceConfig.setClientID(clientId);
remoteServiceConfig.setClientSecret(privateSecret);
RemoteService remoteService = new RemoteService(remoteServiceConfig, authorizationHeaderServiceImpl);
return remoteService;
}
publicmap approvalAction(长documentId,ActionCommandDTO请求,FormData FormData,byte[]prevData){
RemoteService客户端=getRemoteService();
String urlString=String.format(“formExtensions/%s?%s”、formData.getId()、getAuthParam(formData.getRealm());
试一试{
response=client.postEntity(urlString、String.class、approvalSvcRequestStr);
}捕获(例外e){
//TODO:正确处理P2P的回滚
handleApprovalActionFailed(documentId、request、formData、prevData);
}
返回图;
}
私有远程服务getRemoteService(){
RemoteServiceConfig RemoteServiceConfig=(RemoteServiceConfig)this.serviceConfigRegistry.getServiceConfigs().get(“批准”);
remoteServiceConfig.setClientID(clientId);
remoteServiceConfig.setClientSecret(privateSecret);
RemoteService RemoteService=新的RemoteService(remoteServiceConfig,authorizationHeaderServiceImpl);
返回远程服务;
}
将getRemoteService
更改为受保护的
,并使用子类覆盖它:
public class SomeService {
public Map<String, String> approvalAction(long documentId, ActionCommandDTO request, FormData formData, byte[] prevData) {
}
// change here
protected RemoteService getRemoteService() {
RemoteServiceConfig remoteServiceConfig = (RemoteServiceConfig) this.serviceConfigRegistry.getServiceConfigs()
.get("approval");
remoteServiceConfig.setClientID(clientId);
remoteServiceConfig.setClientSecret(privateSecret);
RemoteService remoteService = new RemoteService(remoteServiceConfig, authorizationHeaderServiceImpl);
return remoteService;
}
}
public class TestSomeService extends SomeService {
@Override
protected RemoteService getRemoteService() {
return new MockService();
}
}
公共类服务{
公共映射approvalAction(长文档ID、ActionCommandDTO请求、FormData FormData、字节[]prevData){
}
//在这里换车
受保护的RemoteService getRemoteService(){
RemoteServiceConfig RemoteServiceConfig=(RemoteServiceConfig)this.serviceConfigRegistry.getServiceConfigs()
.获得(“批准”);
remoteServiceConfig.setClientID(clientId);
remoteServiceConfig.setClientSecret(privateSecret);
RemoteService RemoteService=新的RemoteService(remoteServiceConfig,authorizationHeaderServiceImpl);
返回远程服务;
}
}
公共类TestSomeService扩展了SomeService{
@凌驾
受保护的RemoteService getRemoteService(){
返回新的MockService();
}
}
您不能模拟RemoteService,因为它是在您的类中创建的。如果可能的话,将getRemoteService提取到另一个类,让我们称之为NewClass。现在您可以模拟NewClass了
public Map<String, String> approvalAction(long documentId, ActionCommandDTO request, FormData formData, byte[] prevData) {
RemoteService client = NewClass.getRemoteService(params);
///
}
publicmap approvalAction(长documentId,ActionCommandDTO请求,FormData FormData,byte[]prevData){
RemoteService client=NewClass.getRemoteService(参数);
///
}
另一种方法是,如果您不想更改遗留代码,则需要扩展类(实现approvalAction)覆盖getRemoteService()函数。在getRemoteService的新实现中,调用创建模拟RemoteService。您可以测试这个新类。为什么不通过构造函数将
远程服务
注入,但也允许使用默认构造函数
class YourClass{
private final RemoteService client;
public YourClass(RemoteService client){
this.client = client;
}
public YourClass(){
RemoteServiceConfig remoteServiceConfig = (RemoteServiceConfig) this.serviceConfigRegistry.getServiceConfigs().get("approval");
remoteServiceConfig.setClientID(clientId);
remoteServiceConfig.setClientSecret(privateSecret);
client = new RemoteService(remoteServiceConfig, authorizationHeaderServiceImpl);
}
// all of your other methods inside the class
}
当然,您必须调整现有的构造函数。但由于你没有向全班展示,这对我来说是不可能的
这样,在YourClass
的整个生命周期中,只有一个客户机实例
现在很容易模拟
远程服务
。只需使用模拟客户端实例化YourClass
:
RemoteService mock = mock(RemoteService.class);
YourClass toTest = new YourClass(mock);
为什么要更改业务逻辑的代码以便在测试中模拟服务?@Stultuske,在某些情况下:在编写单元测试和涵盖测试场景时,我们可以在业务逻辑中找到一些问题点。因此,在考虑测试用例的同时重构代码可能是合理的。良好的单元测试有助于使体系结构变得更好,但这并不容易。为什么要包含“无需重构”的约束?@AkinerAlkan如果您进行测试驱动开发,那么您的测试是在实现之前编写的。话虽如此,我们谈论的不是(通过测试显示)出现故障的代码,而是更改业务代码以允许测试运行。使用
PowerMock
模拟RemoteService
如何<代码>PowerMockito准确地说就是这种情况。