Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq and Code Contracts

When using class invariants, Code contracts seems to inject code everywhere. Stuff like this

[ContractClassFor(typeof(IX))]
interface IXContract  
{  
    [ClassInvariant]
    void Invariant() { ... }
}

[ContractClass(typeof(IXContract))]
interface IX { event EventHandler b; }

var a = new Mock<IX>();

a.Raise(x => x.b += null);

Fails with an error message

Could not locate event for attach or detach method Void $InvariantMethod$().

Anyone know of a solution?

like image 340
jameszhao00 Avatar asked Jun 17 '11 18:06

jameszhao00


2 Answers

This unit test "passes" when run without generating exceptions:

[ContractClassFor(typeof(IX))]
class IXContract
{
    [ContractInvariantMethod]
    void Invariant() { }
}

[ContractClass(typeof(IXContract))]
public interface IX { event EventHandler b; }

/// <summary>
/// Summary description for UnitTest1
/// </summary>
[TestClass]
public class UnitTest1
{
    public void MyTest()
    {
        var a = new Mock<IX>();

        a.Raise(x => x.b += null);
    }
}

I'm not entirely sure what's going on and how you're compiling (or transcribing) the above, but I don't think you can have "ContractClassFor" attribute decorating an interface, and you certainly can't have the implementation "{ ... }" in an interface. You also need to make your interface IX public to mock it (or else internal with InternalsVisibleTo() castle proxy in your properties).

Hopefully this helps, but feel free to update your post with new code if this doesn't lead you toward what you're looking to do.

like image 104
Erik Dietrich Avatar answered Nov 07 '22 11:11

Erik Dietrich


Your code is incorrect. It should look like this:

[ContractClassFor(typeof(IX))] 
internal abstract class XContract : IX
{   
    // Invariants belong on your actual implemenation; interfaces don't dictate implemenation so this isn't appropariate here.
    // [ ContractInvariantMethod] 
    // void Invariant() { ... } 

    public event EventHandler b { get { return default(EventHandler); } set { }}
} 

[ContractClass(typeof(XContract))] 
interface IX { event EventHandler b; } 

var a = new Mock<IX>(); 

a.Raise(x => x.b += null); 

Notice that the Contract class is Internal Abstract, and that it also now implements your interface. The Invariant isn't appropiate there, as that's for implemenation details; you don't know how people will implemenent your interface, so don't put it there. Also the attribute for invariant methods is ContractInvariantMethodAttribute.

like image 20
Andy Avatar answered Nov 07 '22 12:11

Andy