我正在用 Java 实现一个模型,它需要迭代一个集合并经历多个识别阶段,它涉及 for 循环、while 循环等。这是我想在细粒度级别测试的东西这样我就有信心它已得到正确实现。
我将它作为开始单元测试的机会,因为我认为这对我的代码有益。从那以后,我一直在阅读大量书籍,以跟上 JUnit 和单元测试的速度。
基本上我的问题归结为我收到的两条相互矛盾的建议:
1) 静电是邪恶的。请勿触摸静电。也不要测试 privates,你可能想要一个类。
2) 使用工厂进行创建以允许使用参数进行依赖注入(inject)——可能允许使用模拟和 stub 进行隔离。
在我的示例中,我希望按照以下方式执行操作:
double height = 223.42; // this was set iterating over a collection of doubles
//blah
HeightBounds b = HeightBounds.getHeightBounds(height);
//more blah
我这样做是为了避免建立一个非常长和复杂的代码块,我只能对其进行整体测试。这样我就有了可以测试的公共(public)可访问对象,以确保系统组件都能正确运行。
常识告诉我静态工厂没有任何问题,而且它们很容易测试,但考虑到我正在学习测试驱动设计,我是否遗漏了一些非常明显的东西?
谢谢
最佳答案
静态工厂类在您的类和HeightBounds
类之间引入耦合。这可能会使您的类难以测试,例如,如果 HeightBounds
关闭并在数据库中查找信息,或从 Web 服务读取等等。
如果您改为将 IHeightBounds
实现注入(inject)到您的类中,那么您可以模拟它,以便您可以测试当您的类的依赖项执行某些操作时会发生什么。
例如,如果 HeightBounds
抛出异常怎么办?或返回空?或者您想测试何时返回特定的 HeightBound
?使用接口(interface)很容易模拟这种行为,使用静态工厂则更难,因为您已经制造了数据以在类中创建所需的结果。
您仍然可以只有一个 HeightBounds
的实现,并且能够单独测试它,但是您甚至可以在没有真正的实现的情况下测试上面的方法。
我可能会有一个 IHeightBoundFactory
接口(interface)并将一个实现注入(inject)到类中。
至于测试私有(private),通常你不想。您想要测试两件事中的一件,或者结果是您所期望的,或者交互是您所期望的。
如果您有一个名为 Add
的方法和一个名为 GetAll
的方法,那么您可能想在调用 Add
时测试它,然后调用GetAll
你会取回你添加的那个。您不关心它是如何实现的,只关心它的工作原理。这是测试结果。通常在这种情况下,您希望创建返回数据的模拟对象。这似乎是你的情况。
如果当您调用 Add
时您希望记录添加的内容,那么您想要测试与日志记录依赖项的交互,因此您注入(inject)一个模拟依赖项并验证与它的交互当您调用 Add
时发生类。通常在这种情况下,您希望创建具有预期设置的模拟对象,并验证是否已满足这些预期。在您上述情况下,这看起来没有必要。
关于java - 单元测试、静态和工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5637495/