模拟 IOrganizationService (Dynamics CRM) 时未过滤 LINQ 查询结果
LINQ query results not filtered when mocking IOrganizationService (Dynamics CRM)
我在单元测试查询 Dynamics CRM 2015 的代码时遇到问题。
我使用 Moq 框架并模拟 IOrganizationService
如下:
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);
因此,IOrganizationService
模拟将始终return 相同的预定义帐户列表,无论请求是什么样的。
这是我要测试的代码:
var query = serviceContext.AccountSet.Where(
a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();
当针对真实 CRM 实例执行此代码时,它按预期工作。
使用模拟 IOrganizationService
,代码不再有效。在调试器中,我可以看到 AccountSet returns 是预期的帐户列表(我在模拟期间设置的那个)。但是,Where
方法似乎没有执行,query
包含所有帐户实体。所以,调用 FirstOrDefault
return 只是第一个,而不是调用 Where
方法的结果。
如果我按如下方式修改代码,它在单元测试期间也开始工作:
var query = serviceContext.AccountSet.ToList().Where(
a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();
如果我没理解错的话,这段代码会检索所有帐户,并在本地(而不是在 CRM 中)过滤它们。这对于单元测试来说很好,但在实际应用中是不可接受的。
任何人都可以告诉我做错了什么吗?谢谢!
编辑:
我们最终模拟了 serviceContext
,因为我们直接从客户端代码调用它的方法(或属性),而不是 IOrganizationService
上的方法(或属性)。我认为只有当我们要测试的代码直接使用 IOrganizationService
而不是通过 serviceContext
时,模拟 IOrganizationService
才有意义。否则,我们会有类似两级模拟的东西,它会变得很乱。
请尝试FakeXrmEasy。有一些介绍视频和许多不同的测试示例。
通过使用 FakeXrmEasy,框架已经处理了模拟,因此减少了仅用于设置测试的样板代码量。
我从 2014 年开始研究它,它是 MIT 许可的。实际上,如果有人愿意为该项目做出贡献,那就太棒了! :)
编辑:只是 adding a link 到一个博客 post,它将 FakeXrmEasy 与其他 .NET 模拟框架进行比较。目的无非就是能够为 Dynamics CRM 完成尽可能多的工作。对于其他 .NET 模拟框架,每次模拟的内容基本上太多了。
Where
子句成为针对 OrganizationService
执行的查询的一部分,在您的情况下,无论条件如何,它总是被模拟为 return 完整的 accounts
列表.您可以向您的最小起订量添加更多逻辑,但通常这在单元测试中不是必需的,因为您的目标是测试您的业务逻辑,而不是您模拟 OrganizationService
.
的能力
我在单元测试查询 Dynamics CRM 2015 的代码时遇到问题。
我使用 Moq 框架并模拟 IOrganizationService
如下:
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);
因此,IOrganizationService
模拟将始终return 相同的预定义帐户列表,无论请求是什么样的。
这是我要测试的代码:
var query = serviceContext.AccountSet.Where(
a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();
当针对真实 CRM 实例执行此代码时,它按预期工作。
使用模拟 IOrganizationService
,代码不再有效。在调试器中,我可以看到 AccountSet returns 是预期的帐户列表(我在模拟期间设置的那个)。但是,Where
方法似乎没有执行,query
包含所有帐户实体。所以,调用 FirstOrDefault
return 只是第一个,而不是调用 Where
方法的结果。
如果我按如下方式修改代码,它在单元测试期间也开始工作:
var query = serviceContext.AccountSet.ToList().Where(
a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();
如果我没理解错的话,这段代码会检索所有帐户,并在本地(而不是在 CRM 中)过滤它们。这对于单元测试来说很好,但在实际应用中是不可接受的。
任何人都可以告诉我做错了什么吗?谢谢!
编辑:
我们最终模拟了 serviceContext
,因为我们直接从客户端代码调用它的方法(或属性),而不是 IOrganizationService
上的方法(或属性)。我认为只有当我们要测试的代码直接使用 IOrganizationService
而不是通过 serviceContext
时,模拟 IOrganizationService
才有意义。否则,我们会有类似两级模拟的东西,它会变得很乱。
请尝试FakeXrmEasy。有一些介绍视频和许多不同的测试示例。
通过使用 FakeXrmEasy,框架已经处理了模拟,因此减少了仅用于设置测试的样板代码量。
我从 2014 年开始研究它,它是 MIT 许可的。实际上,如果有人愿意为该项目做出贡献,那就太棒了! :)
编辑:只是 adding a link 到一个博客 post,它将 FakeXrmEasy 与其他 .NET 模拟框架进行比较。目的无非就是能够为 Dynamics CRM 完成尽可能多的工作。对于其他 .NET 模拟框架,每次模拟的内容基本上太多了。
Where
子句成为针对 OrganizationService
执行的查询的一部分,在您的情况下,无论条件如何,它总是被模拟为 return 完整的 accounts
列表.您可以向您的最小起订量添加更多逻辑,但通常这在单元测试中不是必需的,因为您的目标是测试您的业务逻辑,而不是您模拟 OrganizationService
.