C# 我应该使我的自定义单元测试断言类非静态吗?

C# 我应该使我的自定义单元测试断言类非静态吗?,c#,unit-testing,c#-4.0,dynamics-crm-2011,vs-unit-testing-framework,C#,Unit Testing,C# 4.0,Dynamics Crm 2011,Vs Unit Testing Framework,我使用内置的Visual Studio单元测试工具对CRM 2011执行单元测试。许多测试都断言实体的创建 Assert.IsNull(service.GetFirstOrDefault(contact.Id)); (GetFirstOrDefault是一个扩展方法,它尝试从CRM中按id检索联系人,如果找不到,则返回null) 我想创建自己的Assert方法,其操作方式如下: CrmAssert.存在(服务,联系); 起初,我认为从Assert继承是个好主意,但遗憾的是,它是一个静态类。然

我使用内置的Visual Studio单元测试工具对CRM 2011执行单元测试。许多测试都断言实体的创建

Assert.IsNull(service.GetFirstOrDefault(contact.Id));
(GetFirstOrDefault是一个扩展方法,它尝试从CRM中按id检索联系人,如果找不到,则返回null)

我想创建自己的Assert方法,其操作方式如下:

CrmAssert.存在(服务,联系);
起初,我认为从
Assert
继承是个好主意,但遗憾的是,它是一个静态类。然后我创建了一个新的静态类,如下所示:

公共静态类AssertCrm
{
存在公共静态无效(IOOrganizationService,T实体),其中T:实体
{
存在(服务、实体、null、null);
}
存在公共静态无效(IOOrganizationService服务、T实体、字符串消息),其中T:实体
{
存在(服务、实体、消息、空);
}
存在公共静态无效(IOOrganizationService服务、T实体、字符串消息、params对象[]参数),其中T:实体
{
if(service.GetFirstOrDefault(entity.Id)==null)
{
抛出新的AssertFailedException(message==null?String.Format(message,parameters));
}
}
}
这样称呼:

AssertCrm.Exists(服务,联系人);
这很好,只是我真的应该能够设置服务一次,而不必每次都调用它:

AssertCrm.Service=Service;
AssertCrm.Exists(联系人);
资产管理存在(活动);
资产管理存在(等);
但我相信VisualStudio将尝试运行多线程测试,这意味着当我设置
服务
静态属性时,它可能会被不同测试中的不同服务覆盖(以及
ioOrganizationService
不是线程安全的)


我是否需要使我的AssertCrm类成为非静态类,这样我就不必担心多线程?有没有一种更简单的技术我不知道?

你可以将AssertCrm作为一个单例,然后你可以实例化它一次,所有其他调用都将使用同一个实例。

我个人更喜欢使用内置断言库的第一个选项。我看不出尝试用扩展方法或“helper”来包装它有什么好处

如果你真的想走这条路,你可以在
ioorganizationservice
上创建一组扩展方法,这样就不需要一直传递它了。使它更干净一点,但我还是赞成第一种

crmService.AssertExists(contact);

顺便说一句,为什么在“单元”测试中遇到一个真正的CRM实例?在您的测试中,使用mock
iorOrganizationService
进行验证要快得多,也更易于维护。

经过一些额外的研究,我没有发现任何理由认为它应该(必须)是一个静态类,并将其创建为一个非静态类


任何想做类似事情的人都要注意:一定要为所有实例方法创建静态方法重载,因为
ClassName.AssertMethod()
new ClassName().AssertMethod()相比,在大多数情况下确实更有意义

但这并不能防止IOrganizationService出现多线程问题。实际上,我考虑过在IOrganizationService上创建扩展方法。我不太喜欢它,因为您仍然多次定义了IOrganizationService。如果CRM 2013推出了一个完全不同的SDK呢?您可以直接使用它,而不是每次测试都设置属性。谁能说我不是在嘲笑IOrganizationService?这只是一个界面。当我想实际测试一个实体是否是在CRM中创建的时,嘲笑它是毫无意义的。我们90%的代码库的复杂部分不是业务逻辑,而是返回数据的查询。如果您能告诉我如何模拟IOrganizationService,那么如果有人删除我在查询中筛选的列,它将失败,而没有实际命中我正在测试的CRM实例,我洗耳恭听!)@Daz-如果这些测试在CRM服务器上运行,从技术上讲,它们被称为集成测试,而不是单元测试,这没什么大不了的(在我的书中),而且我知道很多人都称它们为单元测试。@Daryl-我在CRM开发工作中的大部分测试也都是关于查询和与CRM平台的其他交互。商业逻辑是最简单的部分,哈!也就是说,我已经不再允许在CRM代码中使用任何硬编码字符串。所有实体、属性、选项集项、关系名称等必须在生成的文件中。然后,作为集成测试的一部分,您只需生成文件并进行构建。这就消除了很多问题。你知道FetchXml是什么吗?您可以对照XSD检查它,但无法编译它!您是否仅使用Linq to CRM>?如果没有,如何生成属性名称?使用反射的自定义实用程序?