无需注入的模拟
(C#、WCF 服务、Rhino Mocks、MbUNit)
我一直在为已经存在的代码编写测试(是的,我知道这是错误的方式,但这就是它在我当前合同中的工作方式)。我已经做了相当多的重构来支持模拟 - 注入依赖项、添加额外的接口等 - 所有这些都改进了设计。总的来说,我的测试经历进展顺利(暴露脆弱性并改善解耦)。对于任何对象,我一直在创建依赖模拟,这很适合我并且有意义。
该应用程序本质上有 4 个物理层。数据库、用于数据访问的存储库层、通过管理(或业务逻辑)层连接到存储库的 WCF 服务,所以自上而下看起来像这样;
世界碳纤维 经理人 存储库 数据库
测试管理器和存储库层非常简单,用Rhino Mocks 模拟依赖关系并将它们注入到被测试的层中。
我的问题是测试 WCF 顶层。由于我的服务没有允许我注入依赖项的构造函数,因此我不确定在测试服务上的公共方法 (ServiceContracts) 时如何模拟依赖项。
我希望这是有道理的,非常感谢任何帮助。我知道 TypeMockIsolator 等,但出于预算和其他原因我真的不想走这条路,我不会在这里讨论。此外,我确信有很多聪明的“堆栈者”拥有我需要的信息。
提前致谢。
(C#, WCF Service, Rhino Mocks, MbUNit)
I have been writing tests for code already in place (yes I know its the wrong way around but that's how its worked out on my current contract). I've done quite a bit of re-factoring to support mocking - injecting dependencies, adding additional interfaces etc - all of which have improved the design. Generally my testing experience has been going well (exposing fragility and improving decoupling). For any object I have been creating the dependant mocks and this sits well with me and makes sense.
The app essentially has 4 physical layers. The database, a repository layer for data access, a WCF service that is connected to the repository via a management (or business logic) layer, so top down it looks like this;
WCF
Managers
Repository
Database
Testing the managers and repository layer has been simple enough, mocking the dependencies with Rhino Mocks and injecting them into the layer under test as such.
My problem is in testing the top WCF layer. As my service doesn't have the constructor to allow me inject the dependencies, I'm not sure how I go about mocking a dependency when testing the public methods (ServiceContracts) on the service.
I hope that's made sense and any help greatly appreciated. I am aware of TypeMockIsolator etc, but really don't want to go down that route both for budget and other reasons I won't go into here. Besides I'm sure there are plenty of clever 'Stackers' who have the info I need.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是否有特定原因导致您的服务无法使用构造函数?
如果没有,您可以使用重载构造函数,其中一个默认构造函数连接默认值,并使用一个参数化构造函数与您的依赖项连接。您现在可以测试参数化 ctor 并依赖默认 ctor 在生产中创建实例。
如果使用依赖项注入,更好的解决方案是使用 WCF IInstanceProvider 接口 用于创建服务实例并通过该注入点提供所需的依赖项。可以找到使用结构图的示例
Is there a specific reason you cant have a constructor on your service?
If not, you can have overloaded constructors with a default constructor wiring up the defaults and one parametrized constructor with your dependencies. You can now test the parametrized ctor and rely on the default ctor for creating the instance in production.
A better solution if you use dependency injection would be to use the WCF IInstanceProvider interface to create your service instance and provide the needed dependencies via that injection point. An example using Structure Map can be found here.
您可以使 WCF 服务成为“管理器”之上的一个薄层,这样它们就很少或没有需要测试的逻辑。那么就不要测试他们,只测试管理者。或者,您可以通过另一个“服务”层来实现类似的效果,其中包含可以测试的服务逻辑,并使实际的 WCF 代码直接传递到该层。
You could make the WCF services a thin layer over the 'managers', so they have little or no logic in them which needs testing. Then don't test them and just test the managers. Alternatively, you could achieve a similar effect by having another 'service' layer which contains the logic from the services, which can be tested, and make the actual WCF code just pass through to that.
我们的 WCF 服务从 Factory 对象获取所有依赖项,并为该服务提供一个采用 IFactory 的构造函数。因此,如果我们想编写一个模拟依赖项之一的测试,例如 IDependency,我们只需要注入一个模拟工厂,该工厂被编程为将模拟的 IDependency 对象返回给服务。
Our WCF service gets all its dependencies from a Factory object, and we give the service a constructor which takes IFactory. So if we want to write a test which mocks one of the dependencies, say an IDependency, we only need to inject a mock factory, which is programmed to give mocked IDependency object back to the service.
如果您使用控制反转 (IoC),例如 Unity、AutoFac 或 Castle Windsor,以及模拟框架(例如 Moq、NMock、RhinoMocks),只要您有正确的设计,这就足够简单了。
有关如何使用 RhinoMock 和 Windsor 进行此操作的良好教程,请查看此博客文章 - http://ayende.com/Blog/archive/2007/02/10/WCF-Mocking-and-IoC-Oh-MY.aspx
If your using an inversion of control (IoC), such as Unity, AutoFac or Castle Windsor, and a mocking framework (eg. Moq, NMock, RhinoMocks) this is simple enough as long as you have the right design.
For a good tutorial on how to do it with RhinoMock and Windsor, take a look at this blog article - http://ayende.com/Blog/archive/2007/02/10/WCF-Mocking-and-IoC-Oh-MY.aspx
如果您使用温莎城堡,请查看WCF 工具,它允许您使用非默认构造函数并将依赖项注入到您的服务中,其中其他事情。
If you're using Castle Windsor, take a look at the WCF facility, it lets you use non-default constructor and inject dependencies into your services, among other things.