如何为CRM 2011插件正确设置C#unit testing?

尝试在CRM 2011中调试插件非常困难。 将.pdb文件放在服务器上的正确位置不仅存在问题,而且每次进行编码更改时,都会遇到部署和重新注册插件的麻烦。 由于触发器是在CRM本身,因此很难为它创建unit testing。

我目前为一个全新的插件编写unit testing的过程相当缓慢而且错误,但是这样的事情:

  1. 使用SDK插件注册工具注册新插件
  2. 将调试器附加到w3wp.exe,在插件代码中添加一个断点。
  3. 通过注册运行的任何操作触发插件。
  4. 当断点被击中时,将管道的preimage,postimage和目标值序列化为XML文件,然后这将成为我的unit testing的输入。
  5. 停止调试并创建一个新的unit testing,使用RhinoMocks模拟PluginExecutionContext和ServiceProvider,使用序列化的XML文件作为输入参数的存根。
  6. 创建在每个unit testing的开始和结束时运行的方法,这些方法重置(首先尝试删除,然后添加)要处理的unit testing的虚拟数据,然后在测试结束时删除虚拟数据。
  7. 编辑序列化文件以引用虚拟数据,以便我可以确保插件在每次运行时都能对抗完全相同的数据。
  8. 在unit testing中声明并实例化插件,传入模拟对象
  9. 执行插件,运行其他查询以确保插件执行我期望的工作,断言失败。

这是一件痛苦的事。 从获得正确的图像到创建虚拟数据,并在每次测试运行时重置它,似乎有很多需要改进的地方。

如何在不必从CRM实际触发插件的情况下对插件进行unit testing,或者首先运行在CRM中调试它的所有箍,并为每个测试创建独特的虚拟数据? 如何使用注入来消除在每个unit testing中删除,创建,测试,validation和删除CRM中的数据的需要?

2016年更新

这个问题仍然有很多点击,所以我想我会添加两个(我所知道的)开源项目,为unit testing提供Fake CRM实例:

  • FakeXrmEasy – 由Jordi创建(见下面的答案)
    • 主要是假的CRM服务
    • 支持插件/工作流程伪造
    • 对FakeItEasy的依赖
    • 好文档
  • XrmUnitTest – 由我自己创建
    • 假CRM服务+更多(假设,实体建设者等)
    • 流畅支持插件/工作流程伪造
    • 没有依赖任何模拟框架
    • Sucky文档(我正在研究它)

查看我创建的video ,比较和对比差异。

如何在不必从CRM实际触发插件的情况下对插件进行unit testing,或者首先运行在CRM中调试它的所有箍,并为每个测试创建独特的虚拟数据?

随着嘲弄。 有关使用RhinoMocks模拟的类, 请参阅此链接 。 在这方面听起来像你在路上。

如何使用注入来消除在每个unit testing中删除,创建,测试,validation和删除CRM中的数据的需要?

注入输入参数的值可以通过在要操作的实体的手摇实例中进行存根来完成:

// Add the target entity Entity myStubbedEntity = new Entity("account"); // set properties on myStubbedEntity specific for this test... ParameterCollection inputParameters = new ParameterCollection(); inputParameters.Add("Target", myStubbedEntity); pipelineContext.Stub(x => x.InputParameters).Return(inputParameters); 

是不是比捕获xml数据和重新整合整个输入参数集更容易?


编辑:对于数据访问,通常的建议是将数据访问包装到类中。 存储库模式很受欢迎,但对于我们在这里需要的东西来说太过分了。 对于你的插件执行类,你在创建时“注入”你的模拟类。 一个空白构造函数,用于初始化默认存储库,第二个构造函数用于获取IRepository。

 public class MyPluginStep { ITaskRepository taskRepository; public MyPluginStep(ITaskRepository repo) { taskRepository = repo; } public MyPluginStep() { taskRepository = new DefaultTaskRepositoryImplementation(); } public MyExecuteMethod(mypluginstepparams){ Task task = taskRepository.GetTaskByContact(...); } 

根据插件步骤的复杂性,这可能演变为将许多存储库传递给每个类,并且可能会变得很麻烦,但这是您可以根据需要增加复杂性的基础知识。

我将插件执行上下文序列化为文件以用于unit testing。 有一个关于codeplex的好项目可以做到这一点http://crm2011plugintest.codeplex.com/

使调试和unit testing更容易,您可以“记录”现实世界的测试。

一个非常好的选择是使用一个模拟库,为你处理模拟和伪造,因为我想创建自己的,并且总是浪费很多时间创建假货或模拟,直到我创建这个库为你做它。 试试FakeXrmEasy