13

我有一种情况,我需要在生产中模拟一些代码。这是为了使一部分代码工作在一半功能上。

我必须选择编写一个空类(实现接口),或者使用 moq 之类的模拟系统。

所以问题是,模拟系统会影响性能,还是会破坏生产代码的某些可读性?

更新
示例:

interface IRocketSystem
{
   void LaunchTheRocket();
}

class SimulationRocketSystem:IRocketSystem
{
...
}

class RocketSystem:IRocketSystem
{
...
}

我发现我在生产中有一个 SimulationRocketSystem 类,那么小而且体内没有很多。模拟系统有一行代码(new Mock < IRocketSystem >().Object)来替换这样的类。

模拟的优点:
项目中的空类较少。

4

8 回答 8

14

听起来像一个空对象。我不相信为此使用模拟框架有两个原因。

首先,它损害了可读性。您使用适当命名的空类实现接口,然后记录该类中的意图。另一方面,如果您使用模拟框架,您的文档需要嵌入到代码中的某个位置。此外,这会让人感到困惑,因为人们倾向于在测试代码中期待模拟,而不了解您使用模拟的意图。

其次,您必须考虑如果有人修改界面会发生什么。如果添加一个方法怎么办?它是否应该默认返回 null - 就像某些框架会做的那样?如果方法必须根据接口约定返回一些特定的返回值怎么办。如果您有具体的实现,那么编译器至少会在一定程度上保护您。如果您使用模拟框架,您可能会不走运。

于 2009-08-02T19:32:57.777 回答
9

模拟对象是您用于测试的东西,因为它可以让您断言它被正确调用。在我看来,您正在寻找的更像是存根或代理对象。

由于您最终将实现有问题的类,因此让一个模拟框架为您 IMO 做这件事几乎没有意义。为什么不直接创建类并根据需要实现它。

于 2009-07-31T10:21:22.663 回答
6

空班有什么问题?

的确,它会被一个真正的类所取代,所以你不妨从一个真正的类开始。

我认为将任何类型的模拟代码放在测试之外都是一个糟糕的政策。

于 2009-07-31T10:07:23.550 回答
2

这可能有点不寻常,所以我会在我的评论等中明确指出这是必需的功能。否则有人会对测试代码如何投入生产感到非常困惑!

至于性能,一如既往,你需要衡量它,因为它是如此具体。但是,我会冒昧地猜测,当你在模拟你没有编写的功能时,它可能比你模拟出来的实现要快得多。这是您可能需要对用户进行教育的事情,因为当您提供最终的功能实现时,他们很可能会看到性能下降:-)

真正的解决方案是为现有接口提供一个虚拟实现,然后再提供真正的实现。

于 2009-07-31T10:03:18.923 回答
2

你称之为模拟,但看起来你所做的只是适当的关注点分离。

在 if 语句上使用多态性来控制应该发生的事情是一件好事。

例如,假设您希望日志记录是可选的。当务之急的方法是提供一个boolean isLogging. 然后每次检查 boolean like if (isLogging) { ...logging code... }

但是,如果您将实际的日志代码分离为另一个对象的关注点,那么您可以将该对象设置为执行您想要的操作的对象。除了具有表示禁用日志记录和实际写入文件的空路由记录器之外,它还允许您提供写入数据库而不是文件的日志记录对象,它允许您向记录器添加功能,例如作为日志文件轮换。

它只是很好的面向对象编程。

于 2009-08-02T14:33:19.827 回答
1

我真的不知道性能问题。但是恕我直言,您必须非常小心可读性。声明一个或多个接口并以两种不同的方式实现它不是更好吗?

- 编辑

模拟可能更容易,并且使用更少的代码行,但它会增加代码的学习曲线。如果一个新人来查看您的代码,他将需要更多时间来理解。就个人而言,我认为这是代码尚未实现的功能。但是如果有另一个接口实现,或者其他一些好的设计决策,我会更快地“得到它”,并且在更改代码时会感觉更安全。

嗯,这是个人意见。您的代码将使用与预期不同的模式。它类似于“约定优于配置”。如果您不使用约定,则应该更难配置它(在您的情况下,记录并明确您在做什么)。

于 2009-07-31T10:05:17.657 回答
1

我的建议-不要将其投入生产。永远不要在生产中放置任何会减慢、破坏或以其他方式导致您失业的东西 :)

但比我认为更重要的是你的公司政策是什么,你的经理是怎么想的?你永远不应该考虑自己做出这样的决定——它被称为 CYA。

于 2009-07-31T12:25:07.653 回答
-1

我必须选择编写一个空类,或者使用 moq 之类的模拟系统。

将其包装在专用的外观/适配器组件中并使用内部类就足够了。如果你的空类需要在系统中传递,你就有问题了。

于 2009-07-31T10:20:03.303 回答