【问题标题】:JUnit testing static counter of objectsJUnit 测试对象的静态计数器
【发布时间】:2016-08-28 19:09:21
【问题描述】:

我是单元测试的初学者,我遇到了一些我不知道如何解决的失败。我试图测试我的简单类 Employee 我有创建对象的静态计数器,因此新员工可以获得连续的数字和默认名称,如“Name1”、“Name2”等。这是我的默认启动块:

    {
    currentNr = ++count;
    setName("Name"+currentNr);
    setSurname("Surname"+currentNr);    
}

我用很少的方法编写了一个 JUnit 类。它们工作正常,但有关计数器的方法只有在我单独运行它们时才起作用(当我将它们保存为单独的测试时它们也起作用,但是有这么多文件似乎很乱)。 当我使用所有测试方法运行该类时,计数器正在添加更多对象,并且我不知道为什么/何时/何处测试是独立的。在测试方法中,我正在创建一个对象并使用 assertEqual 检查计数器。寻找解决方案我尝试使用@Before、@After 等,但它是相同的,或者我可能不知道如何正确使用它。 我的问题是我该怎么做才能让所有测试方法正常工作,或者我应该在 @Before 方法中写什么(我尝试将对象添加和删除到 ArrayList 和/或设置为 null)。我想只有在单独运行时才能进行测试是不可接受的。 任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 能否贴出源码,即Employee类和单元测试?
  • 测试在某种程度上是独立的,但静态字段将继续存在并在测试之间保持其值。
  • 也许在您的测试中,您想在开始和结束时读取计数器的值,然后减去并测试差异是否符合预期?

标签: java unit-testing junit


【解决方案1】:

不要使用静态字段作为员工的计数器。改用实例字段:

public class Manager {
    private int employeesCount;

    public Employee addEmployee() {
        employeesCount++;
        Employee employee = new Employee();
        employee.setName("John " + employeesCount);
        employee.setLastName("Smith " + employeesCount);
        return employee;
    }
}

不使用静态字段(阅读:why static variables are bad)来维护状态有很多很好的理由,其中之一是这会使您的代码不可测试。如果您在对象中(在实例字段中)维护您的状态,那么实例化您的对象并按原样测试它是没有问题的。

相反,请确保您的程序中只有一个 Manager 实例并且每个人都使用它(这称为单例)。嗯,有单例模式。还有很多不使用它的好理由(阅读:why singletons are bad)。所以最终的事实是,当你编写真正的应用程序时,你通常会使用一些依赖注入框架(如 springguice),并且它们能够在你需要时为你实例化单例它。

嗯,这里有点幽默,但我相信你会明白,全局状态被认为是糟糕的实践,而难以测试它是它表现出来的方式之一。

【讨论】:

  • 我使用静态变量的原因是我在讲座中有类似的计数器示例,因此即使没有创建对象,我们也可以检查计数器(不幸的是,没有任何关于测试它的内容)。只是出于好奇 - 所以没有“漂亮”的方法来删除对象并重置计数器?
  • 您可以添加一些静态方法来重置测试计数器,但这在您从多个线程运行测试时不起作用(但如果您按顺序运行它们)。可能有更不漂亮的方法涉及类加载器和类重新加载。所以我的简短回答是,没有很好的方法可以做到这一点。
  • 非常感谢!同样对于那些链接的其他主题,我现在看到了问题。
【解决方案2】:

frenzykryger 的答案提供了很多有价值的见解,但还有更多。

您应该始终牢记SOLID 来看待您的工作。在您的示例中,“单一责任原则”可以指导更好的解决方案。你看,好的面向对象编程是关于创建有用的抽象。而且您放入 Employee 的一些抽象根本不属于那里。

例如,可以创建一个 Employee 类来建模为某个公司工作的人。所以,员工是人,所以他们可能有名字;由于他们是组织的一部分,是的,他们可能有一个 ID。

但是:员工获得了分配的 ID!当你在一家新公司开始工作时,人们不会过来问你:“请告诉我们你的新数字 ID”。相反,有人来找你,告诉你“这是你的数字 ID,别忘了”。

因此,考虑到这一点,一些建议:

  1. 员工没有核心属性的setter。因此,像“ID”或“name”这样的应该被更改的属性应该作为参数传递给构造函数。您根本不创建员工对象,并允许稍后更改该实体的名称或 ID!
  2. 因此,正如另一个答案正确指出的那样:某些外部类,例如“经理”必须跟踪所有“已知”员工;如果添加了一个新 ID,该 Manager 会以某种方式计算出一个新的唯一 ID。

最后:是真的:静态是优秀OO设计中的异常。应该有充分的理由转向 static 字段(可能是常量除外)和方法。 静态总是导致代码紧密耦合——这是要避免的!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-06
    • 2019-12-13
    • 1970-01-01
    • 2014-01-05
    • 2011-03-26
    • 2023-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多