当类有外部依赖时,如何编写有效的单元测试?

jay*_*ity 3 junit integration-testing unit-testing easymock mocking

我是测试驱动开发的新手,无法弄清楚如何为我编写的类编写有效的测试.该类如下(Java):

public class MyServiceClassImpl implements MyService {
    private someExternalClient client;
    private anotherExternalClient anotherClient;

    public MyServiceClassImpl() {
        client = someExternalClient.getInstance();
        anotherClient = anotherExternalClient(client);
    }

    public String methodWhichDoesSomething(String query) {
        return anotherClient.getResponse(query);
    }
}
Run Code Online (Sandbox Code Playgroud)

对于测试,我尝试了几个查询,并将我得到的响应与我期望的响应进行比较(我期待它,因为我知道anotherClient将返回什么).它工作正常但这在技术上是一个集成测试,因为我调用外部依赖.在这种情况下,我不明白如何编写"单元"测试.更具体地说,我不知道如何模拟依赖项,因为字段是私有的,没有setter,构造函数不接受任何参数.即使我创建了它们,我如何用我的模拟"提供"类的实例?我自己也写了这个课程,所以请告诉我是否应该重新设计课程,或者提供入门者和制定者?

Spo*_*ock 5

这是大多数开发人员陷入的非常普遍的情况.如何使代码可测试的问题.经验法则"如果您没有任何安全问题,请不要害怕改变设计,以便您的例程可以测试." 这实际上是一件非常好的事情,因为您的SUT(系统测试)API对其客户很有吸引力,并且更容易进行更改和扩展.

在你的情况下,保持你的集成测试,因为它测试整个系统与数据库交互/配置等.

通常重要的是单元测试.但看着你编码方法 methodWhichDoesSomething(String query)

几乎没有任何行为.它只调用另一个客户端来返回响应.因此,您需要确定是否需要为此编写单元测试.我不建议,因为它没有单元测试的任何行为.

但是如果你真的想要单元测试,那么是否使用期望参数类型调用了GetResponse(..)方法是候选者.

为此,将您的依赖关系NaExternalClient注入您的SUT(系统测试中).

 public MyServiceClassImpl(AnotherExternalClient externalClient)
 {
Run Code Online (Sandbox Code Playgroud)

在您测试设置AnotherExternalClient上的模拟并验证是否已调用该方法.如果您的参数是MyServiceClassImpl的必需类型,请使用此构造函数注入.如果注射是可选的,如果不是简单地使用属性注入.

UPDATE

注册."注入你的依赖"

从anotherExternalClient(clent);返回的实例,它是anotherExternalClient的类型,可以注入到您的SUT(System Under Test)MyServiceClassImpl中.您注入的方式是使用属性或通过构造函数.稍后我会解释一下.您不必担心编写类似client = someExternalClient.getInstance()的代码;

因为这可以外部化并返回客户端,然后用于返回anotherExternalClient.换句话说,你的SUT(被测系统)MyServiceClassImpl应该只关心anotherExternalClient而不是someExternalClient.减少这种依赖性可以简化您的设计并使单元测试更容易.

注册."物业注射与Ctro注射" 我不会重复我的自我,这是另一个SO问题有关于此的一些信息.

希望这可以帮助.

这很关键,因为在单元测试方面,您可以轻松地为您提供用于测试的模拟/虚假实现.