C# 模拟IOrganizationService(Dynamics CRM)时未筛选LINQ查询结果

C# 模拟IOrganizationService(Dynamics CRM)时未筛选LINQ查询结果,c#,linq,unit-testing,dynamics-crm,moq,C#,Linq,Unit Testing,Dynamics Crm,Moq,我在单元测试查询Dynamics CRM 2015的代码时遇到了一个问题 我使用Moq框架并模拟ioOrganizationService,如下所示: IList<Account> accounts = new List<Account> {/*...*/}; IList<IEntity> expected = new List<Entity>(accounts); var collection = new EntityCollection(exp

我在单元测试查询Dynamics CRM 2015的代码时遇到了一个问题

我使用Moq框架并模拟
ioOrganizationService
,如下所示:

IList<Account> accounts = new List<Account> {/*...*/};
IList<IEntity> expected = new List<Entity>(accounts);
var collection = new EntityCollection(expected);
var retrieveMultipleResponse = new RetrieveMultipleResponse
{
    Results = new ParameterCollection
    {
        { "EntityCollection", collection}
    }
};
var mockOrganizationService = new Mock<IOrganizationService>();
mockOrganizationService.Setup(os => os.Execute(
    It.IsAny<RetrieveMultipleRequest>())).Returns(retrieveMultipleResponse);
当针对真实的CRM实例执行此代码时,它会按预期工作

使用模拟的
IOOrganizationService
,代码不再工作。在调试器中,我可以看到AccountSet返回预期的帐户列表(我在模拟期间设置的帐户列表)。但是,
Where
方法似乎没有执行,
query
包含所有账户实体。因此,对
FirstOrDefault
的调用只返回第一个,而不是调用
Where
方法的结果

如果我按如下方式修改代码,它也会在单元测试期间开始工作:

var query = serviceContext.AccountSet.ToList().Where(
                    a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();
如果我理解正确,此代码将检索所有帐户,并在本地(而不是在CRM中)对其进行筛选。这对于单元测试来说很好,但在实际应用中是不可接受的

谁能告诉我我做错了什么?谢谢大家!

编辑

我们最终模拟了
serviceContext
,因为我们直接从客户端代码调用它的方法(或属性),而不是
IOOrganizationService
上的方法(或属性)。我认为,只有当我们要测试的代码直接使用
ioorganizationservice
而不是通过
serviceContext
时,模仿
ioorganizationservice
才有意义。否则,我们有类似于两级模拟的东西,它会变得混乱。

请尝试一下。这里有一些介绍视频和许多不同的测试示例

通过使用FakeXREasy,框架已经处理了模拟,因此减少了仅用于设置测试的样板代码量

我从2014年就开始研究它,它是麻省理工学院授权的。事实上,如果有人愿意为这个项目做出贡献,那将非常棒


编辑:这篇博文将FakeXrmEasy与其他.NET模拟框架进行了比较。其目的只是为了能够为Dynamics CRM完成尽可能多的工作。对于其他.NET模拟框架,每次模拟的内容基本上太多了。

Where子句成为对
组织服务执行的查询的一部分,在您的情况下,该服务被模拟为总是返回完整的
帐户
列表,而不管条件如何。您可以向moq中添加更多逻辑,但在单元测试中通常不需要这样做,因为您的目标是测试您的业务逻辑,而不是模拟
组织服务的能力,您是正确的。在ToList()语句之后,将检索所有行,并使用Linq To对象筛选项。CRM linq提供程序的实现有缺陷且不完整。不要期望使用moq总是会得到与“真实”实现相同的结果。显示更多关于您尝试测试的代码的详细信息,因为它与
serviceContext.AccountSet
相关,这样可以更好地复制您的issue@JeroenHeier,这是我开始学习的众多原因之一。这个自动模拟框架将使您更接近“真实”组织服务的行为。。。而且根本不使用任何模拟工具!:)嗨,Matt,请记住,任何业务逻辑的一个重要部分也是查询。。。有很多连接和过滤器。。。示例:当您使用许多插件或CodeActivity时,这些插件或CodeActivity需要执行查询以检索X条记录以对其执行X操作,那么基本上每个查询都需要一个模拟,因为在每种情况下都需要返回不同的实体列表。@Jordi我同意查询非常重要,但它们只能通过集成和针对实际数据的功能测试进行真正的测试,而不是模拟测试。如果你在写一个单元测试,你的重点是你的业务逻辑,而不是针对orgservice的CRUD操作。嗨@Matt,你试过FakeXrmEasy吗?它有一个查询引擎,运行Fetch、QueryByAttribute、LINQ和QueryExpressions。它的目的是能够在集成测试之前对这些查询进行单元测试。是一个比较从FakeXrmEasy运行的查询与其他模拟框架运行的查询的链接。任何反馈都将非常受欢迎!:)@乔迪:太酷了,在看到你对这个问题的答案之前,我还没听说过。看起来非常有用。实际上,我们最终模拟了
serviceContext
,因为我们直接从客户端代码调用它的方法(或属性),而不是
IOOrganizationService
上的方法(或属性)。我认为,只有当我们要测试的代码直接使用
ioorganizationservice
而不是通过
serviceContext
时,模仿
ioorganizationservice
才有意义。否则,我们会有类似于两级模拟的东西,它会变得混乱。
var query = serviceContext.AccountSet.ToList().Where(
                    a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();