Fin*_*las 47 c# .net-4.0 visual-studio-2010 code-contracts
在我的测试项目中无法访问System.Diagnostics.Contracts.ContractException.请注意,这段代码纯粹是我自己搞乱了我的Visual Studio新副本,但我想知道我做错了什么.
我正在使用VS的专业版,因此我没有静态检查.为了仍然使用代码契约(我喜欢),我认为我的方法可以工作的唯一方法是捕获在运行时抛出的异常,但我发现这不可能.
测试方法
[TestMethod, ExpectedException(typeof(System.Diagnostics.Contracts.ContractException))]
public void returning_a_value_less_than_one_throws_exception()
{
var person = new Person();
person.Number();
}
Run Code Online (Sandbox Code Playgroud)
方法
public int Number()
{
Contract.Ensures(Contract.Result<int>() >= 0);
return -1;
}
Run Code Online (Sandbox Code Playgroud)
错误
Error 1 'System.Diagnostics.Contracts.ContractException' is inaccessible due to its protection level.
编辑
经过一番思考后,我得出了评论中讨论的结论,以及以下内容.给定一种方法,如果这有一个可以用代码合同形式表达的要求,我会写这样的测试.
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void value_input_must_be_greater_than_zero()
{
// Arrange
var person = new Person();
// Act
person.Number(-1);
}
Run Code Online (Sandbox Code Playgroud)
这将确保合同是代码的一部分,并且不会被删除.这将要求Code Contract实际抛出指定的异常.但在某些情况下,不需要这样做.
Jon*_*eet 69
这是故意的 - 尽管测试有点痛苦.
关键在于,在生产代码中,您永远不应该想要捕获合同异常; 它表示代码中存在错误,因此您不应期望任何可能需要在调用堆栈顶部捕获的任意意外异常,以便您可以转到下一个请求.基本上,您不应将合同例外视为可以"处理"的合同例外.
现在,为了测试这是一个痛苦......但你真的想测试你的合同吗?这有点像测试编译器阻止你传入一个string有int参数的方法吗?您已经声明了合同,可以对其进行适当的记录,并进行适当的强制执行(无论如何都要根据设置).
如果您确实想要测试合同例外,您可以Exception在测试中查看并检查其全名,或者您可以处理该Contract.ContractFailed事件.我希望单元测试框架能够随着时间的推移对其进行内置支持 - 但要实现这一目标需要一段时间.与此同时,您可能希望使用实用程序方法来预期合同违规.一种可能的实现:
const string ContractExceptionName =
"System.Diagnostics.Contracts.__ContractsRuntime.ContractException";
public static void ExpectContractFailure(Action action)
{
try
{
action();
Assert.Fail("Expected contract failure");
}
catch (Exception e)
{
if (e.GetType().FullName != ContractExceptionName)
{
throw;
}
// Correct exception was thrown. Fine.
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我有一个转换,不再使用ExpectedException或下面的这个属性,而是编写了一些扩展方法:
AssertEx.Throws<T>(Action action);
AssertEx.ThrowsExact<T>(Action action);
AssertEx.ContractFailure(Action action);
Run Code Online (Sandbox Code Playgroud)
这些允许我更准确地提出异常的位置.
ContractFailure方法示例:
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Cannot catch ContractException")]
public static void ContractFailure(Action operation)
{
try
{
operation();
}
catch (Exception ex)
{
if (ex.GetType().FullName == "System.Diagnostics.Contracts.__ContractsRuntime+ContractException")
return;
throw;
}
Assert.Fail("Operation did not result in a code contract failure");
}
Run Code Online (Sandbox Code Playgroud)
我为MSTest创建了一个属性,其行为类似于ExpectedExceptionAttribute:
Run Code Online (Sandbox Code Playgroud)public sealed class ExpectContractFailureAttribute : ExpectedExceptionBaseAttribute { const string ContractExceptionName = "System.Diagnostics.Contracts.__ContractsRuntime+ContractException"; protected override void Verify(Exception exception) { if (exception.GetType().FullName != ContractExceptionName) { base.RethrowIfAssertException(exception); throw new Exception( string.Format( CultureInfo.InvariantCulture, "Test method {0}.{1} threw exception {2}, but contract exception was expected. Exception message: {3}", base.TestContext.FullyQualifiedTestClassName, base.TestContext.TestName, exception.GetType().FullName, exception.Message ) ); } } }这可以类似地使用:
Run Code Online (Sandbox Code Playgroud)[TestMethod, ExpectContractFailure] public void Test_Constructor2_NullArg() { IEnumerable arg = null; MyClass mc = new MyClass(arg); }
| 归档时间: |
|
| 查看次数: |
10768 次 |
| 最近记录: |