I'm having a hard time trying to ensure that the (quite simple) contracts I wrote for an interface using Code Contracts are being applied.
I have this code in a "shared" dll in one of our projects. The intent is that several of our modules can use the same base infrastructure and implement their own handlers and command types:
[ContractClass(typeof(CommandHandlerContracts<>))]
public interface ICommandHandler<TCommand>
where TCommand : ICommand
{
void Handle(TCommand _command);
}
[ContractClassFor(typeof(ICommandHandler<>))]
public class CommandHandlerContracts<TCommand> : ICommandHandler<TCommand>
where TCommand : ICommand
{
public void Handle(TCommand _command)
{
Contract.Requires<ArgumentNullException>(_command != null);
}
}
If I then run a simple test like this, it fails, because no exception is thrown:
public class TestCommand : ICommand
{
public string Field { get; set; }
}
public class TestHandler : ICommandHandler<TestCommand>
{
public void Handle(TestCommand _command) { }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
[ExpectedException(typeof (ArgumentNullException))]
public void TestMethod1()
{
new TestHandler().Handle(null);
}
}
As soon as I copy/paste the interface and contract class definitions from the other dll onto the test class everything starts working. There seems to be a problem with the fact that the interface is in a different dll from the one where it is implemented.
I'm currently using Visual Studio 2012 and the Microsoft test classes ('Microsoft.VisualStudio.QualityTools.UnitTestFramework') for the unit tests. Both the application and test dlls are targeting the .net4.0 framework.
Code contracts is set to "Standard Contract Requires", full runtime checking and 'DoNotBuild' for the Contract Reference Assembly for both projects (at first I wasn't sure this was needed for the unit test project, but I added it there too to no avail).
I thought this should work out of the gate, am I missing something here?
I had the wrong idea about how Code Contracts actually generated the contract clauses. It turns out it needs contract reference assemblies to be built for all referenced assemblies to ensure runtime checking (it was set to "DoNotBuild" on my projects).
After setting the 'common' project to "Build", the test project was able to create it's own contracts and the exception started to throw.
More discussion about this issue can be found here