对具有多个依赖项的 WCF 服务进行单元测试
我当然希望有人能帮助缓解我的沮丧。我正在尝试找到一种好方法来对我的 WCF 服务实现类进行单元测试,但我发现提供解决方案的每个资源都仅限于仅具有单一方法/操作的服务。
就我而言,我有一个服务类,其中包含多个服务方法/操作。服务类的目的是提供在核心应用程序中实现的行为的接口。因此,每个方法/操作负责:
- 从 调用者
- 验证对象的属性,
- 创建该对象的实例 适用的 Command 对象 操作
- 执行映射Request对象的 Command 对象的属性。
- 执行 Command 对象
- 将结果映射到 Response 对象
- 将响应返回给调用者的
此外,服务方法还处理发生的任何异常并返回 WCF 错误。
我们将 Spring.NET 用于 IoC (DI) 和 AOP。服务类由 Spring 实例化,这允许我们使用 Spring 的 ParameterValidation 方面来执行步骤 2。默认情况下,我们也使用 Spring 来执行步骤 3。
在大多数情况下,所有这些都运行良好。然而,当需要编写单元测试来验证服务方法的行为时,我陷入了困境,试图找出处理服务对多个 Command 对象(每个方法一个)的依赖关系的正确方法。
让我们明确一点,我在模拟 Command 对象(我们使用 Moq,顺便说一句)时没有问题,在进行黑盒测试时也没有问题。我正在尝试对内部逻辑进行白盒测试,例如验证步骤 4 是否正确执行,或者如果 Command 对象抛出异常,服务是否正确处理它。对于这些,我使用 Command 对象的模拟实例。
问题是为被测对象具有多个依赖项的场景寻找最佳实践 - 特别是当我只对其中一个依赖项感兴趣以进行我正在运行的测试时。
DI 的构造函数方法并不实用,因为我需要为构造函数提供与在服务上使用方法一样多的参数(而且可能会很多)。 Setter 注入让我担心,因为 Setter 的存在只是为了测试的目的——而且,在很多情况下,它们的数量会很多。
该服务旨在将步骤 4 委托给虚拟方法,默认情况下,该方法使用 Spring 实例化 Command 对象,但可以使用继承和覆盖方法进行重写以返回模拟。但事实证明这也很笨拙。
因此,在网上翻阅了一篇又一篇展示各种解决方案的文章之后,但正如我所说,仅反映具有一种方法/操作的服务,我正在寻找一种方法的指导,该方法在以下情况下易于实现、维护和扩展:处理包含多种方法和多种依赖项的现实世界服务。
请记住,我无法使用 Spring 注入模拟的 Command 对象,因为我需要引用模拟来设置它们并验证方法的行为。 (更不用说我的测试也依赖于 Spring 正常工作。)
I certainly hope someone can help ease my frustration. I am trying to find a good way to unit test my WCF service implementation classes but every resource that I've found providing a solution is limited to services with only a single method/operation.
In my case, I have a service class which contains several service methods/operations. The purpose of the service class is to provide the interface to behavior that is implemented within the core application. As such, each method/operation is responsible for:
- accepting a Request object from the
caller - validating the object's properties
- creating an instance of the
applicable Command object that
carries out the operation - mapping the Request object's
properties to the Command object. - executing the Command object
- mapping the results to a Response
object - returning the Response to the caller
In addition, the service method handles any exceptions that occur and return a WCF Fault.
We are using Spring.NET for both IoC (DI) and AOP. The service class is instantiated by Spring which allows us to use Spring's ParameterValidation aspect to perform step 2. By default, we use Spring for step 3 as well.
For the most part, all of this is working great. However, when it comes time to write unit tests to verify the behavior of a service method I get bogged down trying to figure out the right way to deal with the service's dependencies on multiple Command objects (one per method).
Let's be clear, I don't have a problem mocking the Command objects (we use Moq, btw) nor do I have an issue doing black box testing. I am trying to do white box testing on the internal logic, such as verifying that step 4 is performed correctly or if the Command object throws an exception, the service handles it correctly. For these I am using mock instances of the Command object.
The problem is finding the best practice for a scenario where the object under test has multiple dependencies - especially when I am only interested in one of them for the test I am running.
The Constructor approach to DI just isn't practical as I would need to have as many arguments to the constructor as I do methods on my service (and that could be quite a lot). Setter-injection concerns me because the setters would only exist for the purpose of testing - and, again, there would be a large number of them in many cases.
The service is designed to delegate step 4 to a virtual method that, by default, uses Spring to instantiate the Command object but van be overridden to return the mock using the inherit-and-override approach. But this has proven to be unwieldy as well.
So, after pouring over article after article online that demonstrate various solutions but, as I said, only ever reflect a service with one method/operation, I am looking for some guidance for an approach that will be easy to implement, maintain and extend when dealing with real-world services that contain multiple methods and multiple dependencies.
Keep in mind that I can't use Spring to inject mocked Command objects because I need references to the mocks in order to set them up and verify the method's behavior. (Not to mention that my tests are then dependent upon Spring working correctly, too.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我通常让我的服务类只是实际功能的薄薄的外观。在这种情况下,您可能会考虑放弃测试服务本身,而是将所有调用委托给多个内部对象之一,这将更容易测试,因为它们更具体。
I usually have my service classes be nothing but thin facades to the real functionality. In that case, you might consider forgoing testing the service itself, but have it delegate all calls to one of multiple inner objects, which would be individually more testable as they would be more specific.
听起来你已经完成了大部分艰苦的工作。
由于您已经在使用 DI 容器,也许您可以简单地创建并注入拦截步骤 3 的 Mock。然后您可以通过 DI 容器接收到的内容以及验证的行为方式来测试前两个步骤,然后您可以让 Mock 返回任何内容您想要测试剩余的步骤。
您已经对 spring.net 产生了很大的依赖,并付出额外的努力来注入您的模拟并强制测试以使用它们,这对我来说听起来很合理。必须有一种方法可以临时修改您的配置以使用特定的 Mock。如果不考虑您的服务使用一个简单的工厂来让您的模拟就位。
Sounds like you have already done most of the hard works.
Since you are already using a DI container perhaps you could simply create and inject Mocks that intercept step 3. You could then what is received by the DI container and how the validation behaves to test the first two steps then you could have the Mock return whatever you want to test the remaining steps.
You have already taken a large dependence on spring.net and going that extra distance to inject your mocks and force tests to use them sounds reasonable to me. There must be a way of modifying your config temporarily to use a specific Mock. If not consider a simple factory to be used by your service to allow you to get your Mocks in place.