Extending a class with final attributes. Mockup
我通常将类的每个属性设置为final(仅适用于将在构造函数中初始化的属性)。
关键是我现在正在实现一个用于测试目的的对象的样机。这个Mockup扩展了它正在模拟的类,这个类有一些最终的属性。因此,我被迫在Mockup对象的构造函数中调用super()构造函数。这打破了Mockup的实用程序,因为我不希望它以普通类的方式初始化所有属性。我宁愿调用Mockup构造函数而不调用super()并做任何我想做的事情。
我的问题是:将属性定义为final是一个好习惯,只要它们会强制你调用Mockup中的类构造函数吗?
编辑:我添加一些代码。在这种情况下的问题是我使用单例,我知道这在测试时不是一个好主意,但在这种情况下我不能改变它。所以我的目的不是在模型中调用这个方法。
1 2 3 4 5 6 7
| public class ReportsDataManager {
private final Map <String, List <String >> translations ;
public ReportsDataManager () {
this. translations = GenericUtils. getTranslation();
} |
}
-
你能发布一些SUT的代码和预期的测试吗? 公共呼叫/消息的序列(当发布到被测试的类时)将导致测试所需的状态是什么? 您不必外部操纵SUT的私有变量。
-
"但在这种情况下,我无法改变它。" 更改! ;)stackoverflow.com/questions/2925459/&
-
被测试的课程是什么样的? 它如何使用ReportsDataManager?
-
你是对的,我应该改变它,但即使我删除了Singletone,我仍然可以解决问题。 只是猜测this.translations以我不喜欢的模式初始化...
当你可以做到时,声明属性final是一个非常好的做法。它赋予了不变性 - 保证线程安全。打破它来模拟是一个坏主意。您的设计应该满足用户的需求,而不是您的测试方便性。
-
我同意你的观点,虽然有时我的测试(在我看来)应该以你编码的方式指导你。这里的情况是在构造函数中我正在调用另一个给我一个值的方法,但是这个方法很复杂所以我不想在Mockup中调用它。哪种方式最好?删除最后的条款?在构造函数外调用此方法?
-
在我看来,删除最终条款不是可行的方法。我不明白"复杂"是什么意思。如果您已经测试了"复杂"方法并证明它有效,为什么不能嘲笑它只是返回您想要的值并继续使用它?
-
复杂的我只是意味着它不只是给属性赋值。我用一段代码编辑了我的问题。在这种情况下,我应该删除Singleton并模拟对象GenericUtils,即方法getTranslation()。以这种方式它必须工作。但是如果案例不是使用Singleton而是调用同一个类的私有方法会怎样。我怎么能摆脱它?我无法覆盖那种方法......
如果你想模拟这个类,给它一个接口并模拟接口。此外,模拟不是存根。听起来你正在创建一个存根,而不是一个模拟。
如果您确实希望创建模拟,请选择一个为您生成接口模拟的库。
-
我喜欢你的观点,我没想到。仅仅为创建Mockup创建界面真的值得吗?
-
该接口还将描述两个类是如何耦合的。我认为这总是(好的,经常)是一个好主意。
-
在这种特殊情况下,将单引号的引用解耦是一个很好的第一步。
-
你怎么做没有接口的模拟?这是毫无意义的。
-
我有时使用接口创建模拟,但在其他情况下我通常做的是扩展我想要模拟的类(在这种情况下它将是:public class ReportsDataManagerMockup扩展ReportsDataManager)然后覆盖我想要的方法。我想我错过了术语
您可以使用标准反射来回避final限制。因为你是在一个模型的上下文中,所以这不会引起太多问题,我想。只要注意多线程问题:JVM将假设该字段遵循final语义并将考虑到这一点进行优化。
-
我不太喜欢这个想法,因为通常不建议使用反射进行单元测试,是吗?
-
我不知道这样的建议。无论如何,您认为所有这些模拟框架使用什么?与runrtime字节码生成相比,反射相当温和。
-
在这里你有一个讨论:stackoverflow.com/questions/2811141/&无论如何使用反射创建模拟可能是一个解决方案,但是直接使用那些已经存在的框架之一是否更有意义?
-
答案的答案是正确的:如果你通过反射调用它来测试你的代码,那显然是一种气味。如果您使用它来设置测试夹具,这是您的情况,那就完全没问题了。
-
好吧,你说服了我,但就我而言,我认为我可以更容易地做到这一点
一般来说,如果你使用的练习使你的代码测试更加困难,那么这种做法可能就是一种气味。
尝试通过设置变量final来确定您想要实现的目标。 protected会被接受吗?
-
尽管如此 - 我喜欢@ Marko使用反射的解决方案。