是否创建用于测试不良做法的私有构造函数?

Bus*_*sch 7 java constructor unit-testing

我遇到了一些Java代码,其中公共构造函数使用一堆new运算符调用一个包私有的构造函数来创建新对象。

public class Thing {

    //public
    public Thing(String param1, int paramm2) {
        this(param1, param2, new Dependency1(), new Dependency2());
    }

    //package-private for the sake of testing
    Thing(String param1, int param2, Dependency1 param3, Dependency2 param4) {
        this.memberVar1 = param1;
        this.memberVar2 = param2;
        this.memberVar3 = param3;
        this.memberVar4 = param4;
    }


    //...rest of class...
}
Run Code Online (Sandbox Code Playgroud)

我认为这是错误的,因为您正在编写代码对其进行测试,而不是编写正确的代码。我想(我能想到的)另外两个选择是创建工厂或PowerMockito在适用时用于注入新对象。就我个人而言,我会写成如下图所示。

public class Thing {

    //public
    public Thing(String param1, int paramm2) {
        this.memberVar1 = param1;
        this.memberVar2 = param2;
        this.memberVar3 = new Dependency1();
        this.memberVar4 = new Dependency2();
    }

    //...rest of class...
}
Run Code Online (Sandbox Code Playgroud)

最佳实践/正确方法是什么?

Cod*_*ind 5

通常,将测试特定的代码包含在任何已发布的内容中都是不好的形式(但是有例外,因此请不要阅读得太仔细)。这有两个原因。

1.外部人员可能会以您从未打算的方式使用测试构造函数,从而浪费了所有精力,因为他们要么没有阅读文档,表明该文档仅用于测试,要么开发人员忘记了对其进行文档化。

假设您想编写一些有用的扩展名,Thing但在Thing的公共/受保护的API中找不到您想要的任何东西。然后,您会发现此程序包私有的构造函数似乎允许您所期望的,后来才发现它破坏了代码。您仍然无法做您想做的事情,并且您浪费了时间探索未成功完成的API部分。这样做的人都会对API持否定态度,并且不太可能将其推荐给其他人。

2.重构程序包名称将破坏内容。

由于Java的默认可见性的工作方式,该测试代码对生产代码中发生的重构不是很有弹性。如果测试代码位于相同的程序包中,则只能调用该构造函数。如果软件包被重命名,则调用该软件包的测试代码将无法访问它,从而导致编译错误。当然,对于任何开发代码和测试的人来说,这都是一个简单的解决方案,但是即使不添加这种小麻烦,重构已经不是很有趣。如果很多人以前能够成功使用软件包专用的东西来满足他们的需求,这将成为一个主要问题-现在他们的所有代码也都被破坏了。

在某些情况下,肯定很难编写可同时在测试和生产环境中运行的代码(例如,仅在应用程序联网时才能运行的功能)。在这种情况下,依赖注入可以成为您的朋友,但是如果可以避免更复杂的测试方案而又不牺牲功能覆盖范围或在您的API中添加钩子(您从未希望其他开发人员看到),则更简单的测试始终是最好的选择。