doNothing方法不适用于void静态方法

时间:2017-07-31 16:06:04

标签: unit-testing powermock

我被分配为一个15年的遗留项目添加单元测试代码覆盖率,该项目未使用IoC和0单元测试。我不允许重构代码,因为它在生产上完美无缺,管理层不希望其他团队参与重构,如QA测试等。

服务类的performService方法有以下代码

public void performService(requestMessage, responseMessage) {
        UserAccount userAccount = requestMessage.getUserAccount();
        GroupAccount groupAccount = requestMessage.getGroupAccount();
        Type type = requestMessage.getType();
        StaticServiceCall.enroll(userAccount, groupAccount, type);
        response.setStatus(Status.SUCCESS);
}

StaticServiceCall.enroll方法正在调用远程服务。我的单元测试是

@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticServiceCall.class)
public class EnrollmentServiceTest {

@Test
public void testPerformService() {      
    mockStatic(StaticServiceCall.class);
    doNothing().when(StaticServiceCall.enroll(any(UserAccount.class), any(GroupAccount.class), any(Type.class)));
    service.performService(requestMessage, responseMessage);
    assertEquals("Enrollment should be success, but not", Status.SUCCESS, response.getStatus);
}

Eclipse抱怨The method when(T) in the type Stubber is not applicable for the arguments (void)

如果测试代码更改为

,Eclipse会停止抱怨
mockStatic(StaticServiceCall.class);
doNothing().when(StaticServiceCall.class);
StaticServiceCall.enroll(any(UserAccount.class), any(GroupAccount.class), any(Type.class));
service.performService(requestMessage, responseMessage);
assertEquals("Enrollment should be success, but not", Status.SUCCESS, response.getStatus);

UnfinishedStubbingException的测试用例失败。我正在使用powermock 1.6.6

2 个答案:

答案 0 :(得分:2)

你的结局存在误解。您认为您需要说doNothing() 什么都不做

这不是必要的!正如这些行

@PrepareForTest(StaticServiceCall.class) ... and 
mockStatic(StaticServiceCall.class);

已经足够了。

您希望在测试期间调用方法时阻止运行该静态方法的“真实”内容。这就是mockStatic()正在做的事情。

换句话说:只要您使用mockStatic(),真实类的完整实现就会被擦除。你只需要使用when / then / doReturn / doThrow,以防你想要发生 else 而不是没有

含义:只删除整个doNothing()行!

答案 1 :(得分:1)

@GhostCat - 谢谢你的回答,它解决了问题,我的错误观念来自这个测试用例

var globalBus = new Bacon.Bus();
var processBus = new Bacon.Bus(); 
function startProcess() {
    globalBus.push(new Bacon.Next());
}

processBus.skipUntil(globalBus).onValue(function() {
    console.log((new Date()).getTime());
});

setInterval(function() {
    processBus.push(new Bacon.Next());
}, 1000);

以下是调用不同服务类的请求消息的基于@Test public void testEnrollmentServiceSuccess() { RequestMessage requestMessage = new RequestMessage(); requestMessage.setName("ENROLL"); ResponseMessage responseMessage = new ResponseMessage(); EnrollmentService mockService = mock(EnrollmentService.class); mockService.performService(any(RequestMessage.class), any(ResponseMessage.class)); mockStatic(ClientManager.class); when(ClientManager.isAuthenticated()).thenReturn(true); ServiceImpl service = new ServiceImpl(); service.performService(requestMessage, responseMessage); verify(mockService).performService(any(RequestMessage.class), any(ResponseMessage.class)); } 类的名称的代码片段

ServiceImpl

虽然测试通过, public void performService(RequestMessage request, ResponseMessage response) { try { if (request == null) { throw new InvalidRequestFormatException("null message"); } if (!ClientManager.isAuthenticated()) { throw new ServiceFailureException("not authenticated"); } // main switch for known services if ("ENROLL".equals(request.getName())) { service = new EnrollmentService(); service.performService(request, response); } else if ("VALIDATE".equals(request.getName())) { ... 中的实际实现被调用,并且由于准系统RequestMessage对象而抛出了异常,然后我用google搜索了doNothing,再次感谢您的澄清