【发布时间】:2016-08-20 05:42:26
【问题描述】:
我是 TDD 的新手,在编写看似简单的单元测试时遇到了设计问题。
被测方法做了两件事:
- 调用将对象 A 转换为对象 B 的私有方法
- 调用另一个将对象 B 作为参数传递的私有方法
类似这样的:
public void doStuff(A objectA) {
B objectB = convertToB(objectA);
processB(objectB);
}
现在,我在哪里测试转换是否正确完成? 流行的观点是使用 TDD 不需要使用 PowerMock 或其他库来测试私有方法。我引用 Practical Unit Testing with JUnit and Mockito 一书:
您可以并且可能应该做的第一件事就是避免这种情况。如何?通过遵循 TDD 方法。想想当您首先编写测试代码时私有方法是如何实现的。答案 也就是说,它们是在重构阶段创建的,这意味着它们的内容完全被测试覆盖 (假设您确实遵循 TDD 规则,并且仅在测试失败时才编写代码)。在这样的 在这种情况下,“应该以某种方式测试的未经测试的私有方法”没有问题,因为 这样的方法根本不存在。
我的下一个想法是使用 ArgumentCaptor 并验证是否使用正确的参数调用了 processB()。但同样,processB() 也是私有的,所以不能这样做。
当然,可以做很多技巧来使我的类可测试——将objectB 保存在类字段中或公开我的私有方法之一。但这会恶化,而不是改进我的设计。
所以,我在这种情况下的问题是:测试转换方法的正确方法是什么?哪些设计改进可以使此代码可测试?
编辑:添加一个真实示例以更好地了解问题:
public class EmailSender {
public EmailResult send(Email email) {
MultivaluedMapImpl formData = prepareFormData(email);
EmailResult emailResult = processEmailRequest(formData);
}
private MultivaluedMapImpl prepareFormData(Email email) {
MultivaluedMapImpl formData = new MultivaluedMapImpl();
formData.add(FROM_KEY, email.getSender());
email.getRecipients().stream().forEach((recipient) -> {
formData.add(TO_KEY, recipient);
});
formData.add(SUBJECT_KEY, email.getSubject());
formData.add(TEXT_KEY, email.getText());
return formData;
}
private EmailResult processEmailRequest(MultivaluedMapImpl formData ) {
Client client = Client.create();
client.addFilter(new HTTPBasicAuthFilter("api", "API_KEY"));
WebResource webResource = client.resource(API_URL);
ClientResponse clientResponse = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).
post(ClientResponse.class, formData);
String resultString = clientResponse.getStatusInfo().getFamily().toString();
EmailResult emailResult = resultString.equals("SUCCESSFUL") ? EmailResult.SUCCESS : EmailResult.FAILED;
return emailResult;
}
}
这里prepareFormData()对应上例中的转换方式。我尝试测试的是转换是否正确。
【问题讨论】:
标签: unit-testing junit mocking tdd