Search code examples
c#.net-4.0moqcode-contracts

Moq's are firing code contracts?


Given this code:

[ContractClass(typeof(DogContract))]
public interface IDog {
  void Eat(object obj);
}

[ContractClassFor(typeof(IDog))]
internal abstract DogContract : IDog {
  public void Eat(object obj) {
    Contract.Requires<ArgumentNullException>(obj != null);
  }
}

var dogMock = new Mock<IDog>();
dogMock.Object.Eat(null); // Throws ArgumentNullException

It seems like the rewriter is somehow putting its behavior into the mocked object, which I didn't really expect. I don't think its a real problem, just unexpected. Anyone know how this is happening?


Solution

  • "Call-site Requires checking" will do it. The rewriter will then put the preconditions into the caller code and not the implementations. So, even though the code in the mocked object can't have been rewritten (it's generated at runtime), the code in the caller can be.

    Here's what the generated code looks like without call-site Requires:

    private static void Main(string[] args)
    {
        Mock<IDog> m = new Mock<IDog>();
        m.Object.Eat(null);
    }
    

    And with:

    private static void Main(string[] args)
    {
        Mock<IDog> m = new Mock<IDog>();
        IDog.V$Eat(m.Object, null);
    }
    

    IDog is a static class that contains all the methods from the IDog interface, along with the preconditions. Here is what Eat looks like:

    internal static void V$Eat(IDog @this, object obj)
    {
        __ContractsRuntime.Requires<ArgumentNullException>(
                          obj != null, null, "obj != null");
        @this.Eat(obj);
    }
    

    So this way, the preconditions will be called even if the code in the class can't have been rewritten.