我有一种情况需要mock生产中的一些代码。这是用于制作代码的一部分,使用一半功能。
我必须选择编写一个空类(实现接口),或者使用像moq这样的模拟系统。
所以问题是,模拟系统是否达到了生产代码的性能或打破了一些可读性?
更新
例如:
interface IRocketSystem
{
void LaunchTheRocket();
}
class SimulationRocketSystem:IRocketSystem
{
...
}
class RocketSystem:IRocketSystem
{
...
}
我发现我在制作中有一个SimulationRocketSystem类,那个小而且在体内没有很多。模拟系统有一行代码( new Mock< IRocketSystem>()。Object )来代替这样的类。
嘲笑的优点:
项目中的空类较少。
答案 0 :(得分:10)
听起来像Null Object。我不相信使用模拟框架有两个原因。
首先,它会损害可读性。使用适当命名的空类实现接口,然后记录该类中的intent。另一方面,如果使用模拟框架,则需要将文档嵌入代码中的某个位置。此外,它会让人感到困惑,因为人们倾向于在测试代码中期望模拟,而不理解你使用模拟的意图。
其次,你必须考虑如果某人修改了界面会发生什么。如果添加方法怎么办?它应该默认返回null - 正如一些框架那样吗?如果方法必须根据接口契约返回某个特定的返回值,该怎么办?如果你有一个具体的实现,那么编译器至少会对你有所保护。如果你使用模拟框架,你可能会运气不好。
答案 1 :(得分:9)
模拟对象是您用于测试的东西,因为它会让您声明它被正确调用。听起来你正在寻找的东西更像是存根或代理对象。
因为你最终会实现有问题的类,所以让一个模拟框架为你做IMO是没有意义的。为什么不创建类并根据需要实现它。
答案 2 :(得分:6)
空课有什么问题?
实际上,它将被一个真正的类所取代,所以你也可以从真正的类开始。
我认为在测试之外放置任何类型的模拟代码都是一个糟糕的政策。
答案 3 :(得分:2)
这可能有点不寻常,所以我会在评论中明确表示这是必需的功能。否则,有人会对测试代码如何投入生产感到非常困惑!
至于性能,你需要测量它,因为它是如此具体。但是,我猜想,当你嘲笑你没有写过的功能时,它可能比你的模拟实现快得多。这可能是您需要教育您的用户的事情,因为当您提供最终功能实施时,他们很可能会看到性能损失: - )
真正的解决方案是为现有接口提供虚拟实现,并在以后提供真正的实现。
答案 4 :(得分:2)
你称之为模拟,但看起来你正在做的只是正确分离关注点。
在if语句中使用多态来控制应该发生的事情是一件好事。
示例,假设您希望日志记录是可选的。必要的方法是提供boolean isLogging
。然后每次检查布尔值,如if (isLogging) { ...logging code... }
。
但是如果您将实际的日志代码分开作为另一个对象的关注点,那么您可以将该对象设置为执行所需的对象。除了具有表示禁用日志记录的空路由记录器和实际写入文件的记录器之外,它还允许您提供写入数据库而不是文件的日志记录对象,它允许您向记录器添加功能,例如作为日志文件轮换。
这只是一个很好的面向对象编程。
答案 5 :(得分:1)
我真的不知道性能问题。但恕我直言,你必须非常小心可读性。声明一个或多个接口并以两种不同的方式实现它是不是更好?
- 编辑
模拟可能更容易,并且使用更少的代码行,但它会增加代码的学习曲线。如果一个新人来看你的代码,他将需要更多的时间来理解。就个人而言,我认为这是一个尚未实现的代码功能。但是如果有另一个接口实现,或者其他一些好的设计决策,我会“更快地”获得它,并且在更改代码时感觉更安全。
嗯,那是个人观点。您的代码将使用与预期不同的模式。它类似于“约定优于配置”。如果您没有使用该约定,您应该更难配置它(在您的情况下,记录并明确您正在做的事情)。
答案 6 :(得分:1)
我的建议 - 不要把它投入生产。不要在生产中放置任何可能减慢速度,破坏它或导致你失去工作的东西:)
但比我想的更重要的是你的公司政策是什么以及你的经理的想法是什么?你永远不应该想到自己做出这样的决定 - 它叫做CYA。
答案 7 :(得分:-1)
我必须选择写一个空类,或使用像moq这样的模拟系统。
将它包装在专用的Facade / adapter组件中并使用内部类就足够了。如果需要在系统中传递空类,则会出现问题。