这是我必须测试的课程:
public class Downloader {
public String download(String uri) {
HttpClient client = this.getHttpClient();
client.setURI(uri);
return client.get();
}
private HttpClient getHttpClient() {
HttpClient client = new HttpClient();
// + some config
return client;
}
}
很简单。现在我想在getHttpClient()
抛出异常时测试它的行为。但是,我无法模拟此方法,因为它是private
。这种情况下的常见做法是什么?
答案 0 :(得分:3)
我会使HTTPClient成为构建时(通过接口)设置的类的字段。然后你就可以创建一个模拟的HTTPClient,如果你愿意,可以在测试期间抛出异常,例如:
public class Downloader {
private IHTTPClient client;
public Downloader(IHTTPClient client) {
this.client = client;
}
public String download(String uri) {
this.initialiseHttpClient();
client.setURI(uri);
return client.get();
}
private HttpClient initialiseHttpClient() {
// + some config
}
}
然后使用生产代码中的真实HTTPClient和测试代码中的Mock调用构造函数。您可能需要为实际代码创建HTTPClient的包装器。
答案 1 :(得分:1)
如果您正在尝试测试私有方法,我认为某些方面并不完全正确。
您应该根据合同测试您的课程。私有方法依赖于实现,因此(从某种意义上说)它们的作用并不重要。您应该检查您的公共方法在功能和非功能方案中是否按预期工作,并将其反映到客户端(在本例中为您的测试类)。
你可能需要将某些功能替换到你的类中以用于测试目的(例如在破坏的JDBC连接中替换等)。在那种情况下,我会调查模拟和依赖注入。
答案 2 :(得分:0)
听起来确实有点俗气,但我通常会把这样的方法公之于众,加上显眼的javadocs说“这种方法只是公开测试”。
您也可以通过将xunit / mock等放在同一个包中来使用仅包访问。
我倾向于使用像这样的简单解决方案,而不是像AOP风格的代码注入那样更复杂和难以调试的技术。
答案 3 :(得分:0)
你可以让getHttpClient()受到保护并在测试中将其子类化以返回你想要的东西,所以你在测试中会有这样的东西:
public class TestableDownloader extends Downloader {
protected HttpClient getHttpClient() {
throw new Exception();
}
}
这不是理想的,你最好有一个不同的设计,不需要你测试私有方法(可能使用依赖注入提供工厂或其他东西)。
答案 4 :(得分:0)
私人方法不应该进行单元测试。您只应该对公共方法进行单元测试。如何在内部组织公共方法与单元测试无关。单位不等于方法。它等于可能使用多种方法来完成其工作的行为。
模拟也是一件无用的事情。如果你必须模拟一些东西,你的方法实际上是集成函数。你的代码需要重构才能使它只做一件事,然后一个包装器方法调用它和被模拟的对象来集成它。
单元测试听起来像你应该做的事情,但实际上是浪费你最好在编写应用程序时使用。单元测试不能保证更好的代码质量,也许它会使它变得更糟,因为你没有在你的真实代码上花费足够的时间。