代码之家  ›  专栏  ›  技术社区  ›  yegor256

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

  •  1
  • yegor256  · 技术社区  · 14 年前

    这是我要测试的课程:

    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 回复  |  直到 14 年前
        1
  •  3
  •   Jackson Pope    14 年前

    我将使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创建一个包装器。

        2
  •  1
  •   Brian Agnew    14 年前

    如果你试图测试私有方法,我认为有些事情不太对。

    你应该用它来测试你的班级 合同 . 私有方法依赖于实现,所以(在某种意义上)它们做什么并不重要。您应该检查您的公共方法是否在正常运行和非正常运行的场景中都按预期工作,并将其适当地反映回客户端(在本例中,是您的测试类)。

    可以 为了测试的目的,需要在类中替换一些功能(例如,在断开的JDBC连接中替换等),在这种情况下,我将研究模拟和依赖注入。

        3
  •  0
  •   seand    14 年前

    这听起来确实有点俗气,但我通常会将类似这样的方法公开,并添加引人注目的javadocs,说明“此方法仅在测试时公开”。

    您还可以通过将xunit/mock等放在同一个包中使用package-only访问。

    我倾向于使用像这样简单的解决方案,而不是像AOP风格的代码注入这样更复杂、更难调试的技术。

        4
  •  0
  •   Grant Crofton    14 年前

    您可以将getHttpClient()设置为受保护,并在测试中对其进行子类化以返回所需的内容,因此您的测试中会有类似的内容:

    public class TestableDownloader extends Downloader {
    
      protected HttpClient getHttpClient() {
        throw new Exception();
      }
    }
    

    不过,这并不理想,最好采用不同的设计,不需要测试私有方法(可能使用依赖注入来提供工厂或其他东西)。

        5
  •  0
  •   Ashif M    14 年前

    私有方法不应该得到单元测试。你只需要单元测试公共方法。公共方法如何在内部组织对单元测试来说并不重要。单位不等于方法。它等于可能使用多个方法来完成其工作的行为。

    嘲笑也是没用的。如果您必须模拟某个东西,那么您的方法实际上是集成函数。您的代码需要重构,以使它只做一件事,然后包装器方法调用它和被模拟对象来集成它。

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