我最近在我的解决方案中添加了代码合同。经过一些修改后,我们的构建运行没有任何问题,但由于代码合同,我们的单元测试失败。
环境:
Debug
和Release
DoNotBuild
BuildServer
标记
/p:CodeContractsEnableRuntimeChecking=false;CodeContractsReferenceAssembly=false
来自构建服务器的示例错误文本:
测试方法 Web.Tests.AccountControllerTests.CreateAccount_Pass_NoPasswordSend_Test 引发异常:System.Diagnostics.Contracts.ContractException:An 必须使用代码重写程序集(可能是“Cms.Web”) 合同二进制重写器(CCRewrite),因为它正在调用 Contract.Requires和CONTRACTS_FULL符号是 定义。删除CONTRACTS_FULL符号的任何显式定义 从你的项目和重建。
我已经检查了构建服务器的诊断输出,并且没有可以在任何地方找到的符号CONTRACTS_FULL
。
我不想在构建服务器上启用代码合同,主要是因为我之前没有成功,并且由于时间限制我放弃了(经过更多搜索后我得出的结论是,这是不可能的因为Microsoft不允许在构建服务器上安装自定义扩展)。我只是想忽略构建服务器上的代码契约,但单元测试执行似乎没有这样做。
任何人对我需要查看的位置有任何想法,以确保单元测试忽略代码合同?看起来这应该是可能的吗?也许我可以在构建定义中设置另一个标志,它将被单元测试选中?
修改
请注意,构建服务器在云中作为Microsoft服务 HOSTED ,作为Visual Studio Team Services(以前称为Visual Studio Online)的一部分。这意味着它不是我们的构建服务器,我们无法控制构建服务器上安装的内容。即便如此,我们仍希望使用代码合同。下面接受的答案是一种允许这种情况的方法。
答案 0 :(得分:6)
请阅读代码合同手册。它告诉你需要知道的一切。您不需要在方法上定义任何ConditionalAttribute
。如果你知道这样做的要求是什么,你可以使用Contract.Requires<TException>(bool condition)
。
正如@Mixxiphoid在答案中所说,因为他们使用的是通用形式的Requires,所以需要在构建服务器上安装代码契约和 Peform Runtime Contract Checking 调试配置外,还需要为Release配置启用。
如果您使用的是代码约定,那么始终需要在构建调试版本的构建服务器上安装代码契约。您的团队也是如此:所有需要编译代码的开发人员都需要为Debug版本安装代码契约。
全部在“代码合同”手册中的第5部分:使用指南中。 第20页上有一个有用的图表,可以很好地总结各种使用方案及其要求。
Contract.Requires<TException>(bool condition)
首先,为代码合同 编写此方法的开发人员 忘记将ConditionalAttribute
应用于该方法,正如接受的答案所述。离得很远。该方法未使用该属性修饰的事实是 按设计 。
如果您阅读第5部分:使用指南,您会看到如果您使用Requires
方法的此形式,那么您需要使用二进制重写器 - {{1} - 建立你的装配时。这意味着任何构建程序集的机器都必须ccrewrite
可用。
那么,你可能无法控制的构建服务器呢?我很高兴你问。
关于TFS托管构建服务器:您不能简单地在构建服务器上安装代码约定。那你有什么选择呢?
ccrewrite
或仅限于使用Contract.EndContractBlock()
(非通用形式),或两者的混合。
上面链接的博客文章提供了修改TFS托管构建控制器托管构建的说明。
更新:代码合约的数量很大 对于那些使用托管构建服务的人,例如Visual Studio Online,AppVeyor等,新的社区驱动的Code Contracts GitHub repo最近宣布 v1.10.xxxxx.RC1 。在发行说明中,他们提到NuGet version of code contracts。享受。
答案 1 :(得分:4)
仔细检查后,此构建配置在单元测试中也与构建服务器上的错误相同。经过一番挖掘后,我想出了答案。
答案在于Contract.Requires
。方法Contract.Requires<T>
的通用版本不会将属性[Conditional("CONTRACTS_FULL")]
应用于非泛型方法Contract.Requires
。这意味着始终会评估Contract.Requires<T>
,并且您无法对其进行任何操作。有关详细信息,请参阅Cutting Edge - Code Contracts Settings in Visual Studio 2010。
我恢复了所有代码以使用Contract.Requires
代替Contract.Requires<T>
后,所有单元测试都能够再次执行。您仍然可以使用ContractClassFor
和ContractClass
属性并在合同类中使用通用Contract.Requires<T>
实现而没有任何问题,这是因为合同类不会在没有{{{ 1}}。
答案 2 :(得分:1)
今天早上得到完全相同的问题。解决方案是在发布模式上启用运行时协定检查,而不是仅启用调试模式。
除此之外,CodeContracts也必须安装在构建服务器上。