有没有办法如何使用Code契约测试合约?

时间:2014-02-24 19:12:54

标签: c# .net exception tdd code-contracts

我想编写单元测试来验证我的方法不接受无效参数。使用Code Contract的Contract.Requires调用检查参数的有效性。我为什么要测试合同?我认为我的测试是一种方法规范(实际上是从TDD中获取的),所以通过测试方法对某些参数失败,我指定不应该使用这些参数。

问题在于,由于我开始使用代码契约,因此无法测试方法契约,因为我无法访问Contract.Requires引发的异常。我可以捕获泛型Exception,但这并不好......有没有推荐/支持的方法如何使用代码合同测试合同集?

在我看来,Code Contracts并不真正支持单元测试...


编辑:我的测试示例(我被迫捕获一般异常)

[ExpectedException(typeof(Exception), AllowDerivedTypes = true)]
public void Compute_Throws_ForNullArgument()
{
    new ComputingService().Compute(null);
}

3 个答案:

答案 0 :(得分:3)

您可以加入Contract.ContractFailed事件。

  

http://msdn.microsoft.com/en-us/library/system.diagnostics.contracts.contract.contractfailed(v=vs.110).aspx

这将在抛出异常之前引发。您可以将此与捕获Exception结合起来,以确定它代表合同失败

public void VerifyContract(Action action) { 
  bool failed = false;
  bool thrown = false;
  EventHandler e = (sender, e) => { failed = true; }
  Contract.ContractFailed += e;
  try { 
    action();
  } catch (Execption) {
    Assert.True(failed);
    thrown = true;
  } finally {
    Contract.ContractFailed -= e;
  }
  Assert.True(thrown);
}

答案 1 :(得分:2)

您无法显式捕获正确的异常类型,但您可以捕获Exception,然后使用反射检查它是ContractException(否则重新抛出)。

到处这样做会很难看,但你只需要做一次:

public static void AssertContractFailure(Action action)
{
    try
    {
        action();
        Assert.Fail("Expected contract violation");
    }
    catch (Exception e)
    {
        if (...) // I can't remember offhand what you'd need to check
        {
            throw;
        }
    }
}

然后:

AssertContractFailure(() => SomeContractViolation(...));

目前,如果您在帮助程序类中拥有该程序,则需要在任何地方限定呼叫,但从C#6起,您希望能够轻松导入它:)

答案 2 :(得分:0)

如果我没记错的话,如果Requires构造失败,并且Return构造失败,则合同会抛出异常。因此,对于单元测试目的,您只需要捕获这些异常,并且您将知道合同是否被违反。