Why can't you catch exceptions in Code Contract?

System.Diagnostics.Contracts.ContractException is not available in my test project. Please note that this code is purely I mess with my radiant new copy of Visual Studio, but I would like to know what I'm doing wrong.

I use the professional edition of VS, so I do not have a static check. To still use code contracts (which I like), I decided that the only way my method could work was to catch an exception that was thrown at runtime, but I did not find it possible.

Testmethod

[TestMethod, ExpectedException(typeof(System.Diagnostics.Contracts.ContractException))] public void returning_a_value_less_than_one_throws_exception() { var person = new Person(); person.Number(); } 

Method

 public int Number() { Contract.Ensures(Contract.Result<int>() >= 0); return -1; } 

Mistake

  Error 1 'System.Diagnostics.Contracts.ContractException' is inaccessible
 due to its protection level. 

Edit

After some thought, I came to the conclusion discussed in the comments, as well as the following. Given the method, if this has a requirement that can be expressed in the form of a contract code, I would write tests as such.

 [TestMethod] [ExpectedException(typeof(ArgumentException))] public void value_input_must_be_greater_than_zero() { // Arrange var person = new Person(); // Act person.Number(-1); } 

This will ensure that the contract is part of the code and will not be deleted. This would require the Code Contract to actually throw the specified exception. In some cases this is not required.

+44
c # visual-studio-2010 code-contracts
Apr 14 '10 at 18:26
source share
4 answers

This is intentional - although a little pain for testing.

The fact is that in production code you will never want to catch a contract exception; this indicates an error in your code, so you should not expect this to be more than arbitrary unexpected exceptions that you might want to catch at the top of the call stack so you can move on to the next request. Basically, you should not consider contract exceptions as those that can be "handled" as such.

Now, to check that pain ... but do you really want to check your contracts anyway? Doesn't this look like testing that the compiler stops you from passing to string method that has an int parameter? You have announced a contract, it can be documented accordingly and enforced (depending on the settings, in any case).

If you want to test contract exceptions, you can either catch a bare Exception in the test, or check its full name, or you can get around using Contract.ContractFailed . I would expect modular testing modules to have built-in support for this over time, but it will take a little time. In the meantime, you probably want to use the utility method to expect a breach of contract. One possible implementation:

 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. } } 
+65
Apr 14 '10 at 18:32
source share

EDIT: I had a conversion and no longer use an ExpectedException or this attribute below, but rather some extension methods are encoded:

 AssertEx.Throws<T>(Action action); AssertEx.ThrowsExact<T>(Action action); AssertEx.ContractFailure(Action action); 

This allows me more precisely about where the exception occurs.

ContractFailure Method Example:

  [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"); } 



I created an attribute for MSTest, which behaves similarly to ExpectedExceptionAttribute:

 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 ) ); } } } 

And this can be used in a similar way:

  [TestMethod, ExpectContractFailure] public void Test_Constructor2_NullArg() { IEnumerable arg = null; MyClass mc = new MyClass(arg); } 
+8
Aug 05 '11 at 7:17
source share

in vs2010 rtm, the full name has been changed to "System.Diagnostics.Contracts .__ ContractsRuntime + ContractException". NTN

+2
May 14 '10 at 16:55
source share

Although this question is aging and the answer has already been put, I feel that I have a good solution that simplifies and reads things. In the end, it allows us to write tests for preconditions as simple as:

 [Test] public void Test() { Assert.That(FailingPrecondition, Violates.Precondition); } public void FailingPrecondition() { Contracts.Require(false); } 

Ok, so the idea is to provide the Code Contracts rewriter with its own class of contract runtime. This can be configured in the assembly properties in the section "Methods of user rewriting" (see Section 7.7 of the User Guide for Contract Contracts):

one

Remember to also check Call-site Requires Checking !

A custom class looks something like this:

 public static class TestFailureMethods { public static void Requires(bool condition, string userMessage, string conditionText) { if (!condition) { throw new PreconditionException(userMessage, conditionText); } } public static void Requires<TException>(bool condition, string userMessage, string conditionText) where TException : Exception { if (!condition) { throw new PreconditionException(userMessage, conditionText, typeof(TException)); } } } 

Using the custom class PreconditionException (there is nothing unusual in it!). In addition, we add a small helper class:

 public static class Violates { public static ExactTypeConstraint Precondition => Throws.TypeOf<PreconditionException>(); } 

This allows us to write simple, readable pre-condition tests, as shown above.

+1
Jan 16 '16 at 20:02
source share



All Articles