【发布时间】:2016-03-23 05:20:18
【问题描述】:
以下是我们所做工作的基本理念:
- 网站以表单的形式从用户那里收集数据并将其全部保存到表中的一行中,我们将其称为 FooObject。
- FooObject 然后被传递到业务逻辑类中
- 根据 app.config 中的键,工厂类将实例化三个具体类之一:
- XMLStringA : IFooInterface
- XMLStringB : IFooInterface
- XMLStringC : IFooInterface
- 每个类都有两种方法:
- GenerateXML(FooObject fooObject)
- ParseResponse(string serviceCallResponse)
- 在类实例化后,我们调用 GenerateXML(),传入 FooObject,取回一个 XML 字符串,然后将其提交给三个独立的外部第三方 Web 服务中的任何一个。 (服务的地址也在app.config中。)
- 我们得到响应,并将其发送到 ParseResponse()
一切都好。但是,C 有一些额外的要求。向该服务提交 XML 时,其中一个 XML 元素需要大量查找。我们决定将查找所需的数据添加到数据库中的表中。因此,在 XMLStringC 中有一个私有方法,它使用 EF 进行 DB 调用并获取所需的数据以添加到 XML 字符串中。
我有点意识到这样做违反了单一职责原则,因为这些类实际上应该只是构建一个 XML 字符串。 A 和 B 类不调用 DB。
当我尝试进行单元测试以测试 A、B 和 C 时,我所做的可能愚蠢的事情被赶回家了。由于在运行单元测试时我们不在上下文中,因此 C 在尝试调用数据库。
我不确定在哪里为 C 执行此自定义逻辑。一方面,它仅在我们要提交到 C 服务时发生,因此在 C 类中执行此操作是有意义的。另一方面,我不喜欢从该类内部进行数据库调用。最终,如果我能弄清楚如何对其进行单元测试并使其工作,这可能并不重要。
这样做的最佳做法是什么?
【问题讨论】:
-
为什么不将 C 需要的任何参数作为参数传递给 C 而不是让它进入数据库?这样,在进行单元测试时,您可以只传递一个模拟对象。
-
如果我这样做了,那么 A、B 和 C 都需要它。但是A和B并不在意。它们都实现了相同的接口。
-
如果您使用对象来解决它,则不会。传递一个类
ExternalDependencyProvider,它有一个方法GetExternalData,它执行数据库查找。在您的应用程序中,您构建了一个进入数据库的子类,在您的单元测试中,您传递了一个返回静态对象的类的版本。如果从未调用 GetExternalData(A 和 B),则不会造成任何损害,如果是(C),那么您将获得数据。 -
这一切都是有道理的,但只有一件事。在实例化 A B 或 C 时,我不希望逻辑说“如果 C 则传入 ExternalDependencyProvider”。
标签: c# .net entity-framework unit-testing factory-pattern