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

时间:2014-11-19 06:01:02

标签: unit-testing junit mocking integration-testing easymock

我是测试驱动开发的新手,无法弄清楚如何为我编写的类编写有效的测试。该类如下(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);
    }
}

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

1 个答案:

答案 0 :(得分:5)

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

在您的情况下,请保持您的Integration Test不变,因为它使用数据库交互/配置等测试整个系统。

一般来说重要的是单元测试。但看着你编码方法 methodWhichDoesSomething(String query)

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

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

为了将您的依赖关系NaExternalClient注入您的SUT(系统测试中)。

 public MyServiceClassImpl(AnotherExternalClient externalClient)
 {

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

<强>更新

<强>注册。 “注意你的依赖”

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

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

<强>注册。 “物业注射与Ctro注射” 我不会重复我的自我,here is another SO question有一些关于此的信息。

希望这有帮助。

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