我只是在.Net 4.0中玩代码合约,并且必须缺少一些明显的东西,因为它们没有像我期望的那样表现。
我总是使用一个简单的if ... then .. throw语句在函数开头执行任何验证。
if (hours < 0 || hours > 8)
throw new ArgumentOutOfRangeException("hours", "Hours must be between 0 and 8");
我只是将其替换为
Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8");
但它似乎从未在我的单元测试中引发问题。
public static DurationUnit HoursAsDuration(int hours)
{
Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8");
switch (hours)
{
case 1:
case 2:
return DurationUnit.Quarter;
case 3:
case 4:
return DurationUnit.Half;
case 5:
case 6:
return DurationUnit.ThreeQuarter;
case 7:
case 8:
return DurationUnit.Full;
default:
return DurationUnit.None;
}
}
[Test]
public void CanConvertToDuration()
{
Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(0));
Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(1));
Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(2));
Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(3));
Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(4));
Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(5));
Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(6));
Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(7));
Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(8));
//Would expect this to cause an issue
Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(9));
}
测试返回true,但我原本期望代码合同停止“9”的值进入switch语句。这是预期的行为吗?
答案 0 :(得分:1)
如果你的函数规范用英语表示,它接受hours
的任何值,并在hours
不在0..8范围内时引发异常,那么它的合同(用英文表示)代码契约语言)并不要求hours
介于0和8之间。正确的翻译是函数不需要任何东西,它确保如果hours
在错误的范围内,已经引发了异常,它确保如果hours
在正确的范围内,则进行了正确的计算。
我希望有一种方法可以在代码合同中表达这些内容,但我不熟悉这种合同语言,只有另一种合同语言。但理念是相同的:如果您希望检查是生产构建的一部分,那么检查的条件不是先决条件。另一方面,合同可以(应该)表明支票已经完成并且每个案件都得到了适当的处理。
答案 1 :(得分:0)
好的,我现在通过启用visual studio中项目属性中的“执行运行时合同检查”选项来抛出预期错误。
这是否意味着当发布到生产时代码合同被有效忽略?
我很容易误解如何使用代码合同,所以如果有人能指出我的最佳实践文章的方向,我将不胜感激。
msdn页面说明:
“合同类中的大多数方法都是有条件编译的;也就是说,只有在使用#define指令定义特殊符号CONTRACTS FULL时,编译器才会发出对这些方法的调用.CONTRACTS FULL允许您在合同中写入合同不使用#ifdef指令的代码;你可以生成不同的构建,有些是契约,有些是没有。“
这是否意味着我仍然会更好地使用if .. then .. throw .. for public facing?参数验证检查确实有助于减少数据损坏,因为它会尽早标记故障点。
答案 2 :(得分:-1)
我认为你需要在你的小时参数上交换测试。
您应该定义将通过的规则。
所以我认为这对你有用......
Contract.Requires<ArgumentOutOfRangeException>(hours < 0 && hours > 8, "Hours must be between 0 and 8");