如何设计可用于模拟的私有/最终方法?

时间:2010-11-15 15:39:19

标签: java unit-testing mocking

这是我必须测试的课程:

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。这种情况下的常见做法是什么?

5 个答案:

答案 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)

私人方法不应该进行单元测试。您只应该对公共方法进行单元测试。如何在内部组织公共方法与单元测试无关。单位不等于方法。它等于可能使用多种方法来完成其工作的行为。

模拟也是一件无用的事情。如果你必须模拟一些东西,你的方法实际上是集成函数。你的代码需要重构才能使它只做一件事,然后一个包装器方法调用它和被模拟的对象来集成它。

单元测试听起来像你应该做的事情,但实际上是浪费你最好在编写应用程序时使用。单元测试不能保证更好的代码质量,也许它会使它变得更糟,因为你没有在你的真实代码上花费足够的时间。