Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combination of Moq and Equals() crashing the MS Testing framework

I have what I think should be a very simple test case, but every time I run it QTAgent32 dies. Running the test case in Debug mode shows a System.StackOverflowException being thrown in 'Unknown Module'. I've narrowed it down to the most basic implementation that exhibits this behavior (.NET 4 and VS 2010 Ultimate):

[TestClass]
public class StackOverflow
{
    [TestMethod]
    public void CreateStackOverflow()
    {
        var mockMyType1 = new Mock<MyType>();
        mockMyType1.Setup(m => m.Equals(mockMyType1.Object)).Returns(true);

        var mockMyType2 = new Mock<MyType>();

        // Real test is for a filtering routine and the Assert is using
        // Contains(), but it uses Equals() internally so it has the same problem
        Assert.IsTrue(mockMyType1.Object.Equals(mockMyType1.Object)); // returns true
        Assert.IsFalse(mockMyType1.Object.Equals(mockMyType2.Object)); // explodes
    }
}

public class MyType
{
    public virtual bool IsActive { get; set; }
    public override bool Equals(object obj)
    {
        return false;  // Not the real implementation but irrelevant to this issue
    }
}

I feel like I'm missing something important about closures or maybe Moq, but it seems like this should work. Things I have tried, attempting to understand the issue, but have only confused me more:

  • I tried replacing the Equals() setup with mockMyType.Setup(m => m.Equals(m)).Returns(true); but that causes Moq to throw an NotSupportedException
  • If I make CallBase true instead of setting up Equals(), everything works
  • Finally, if the MyType class doesn't override Equals(), everything works.

Can anyone point me in the direction of what might be happening? I'm completely at a loss.

Edit: I believe I have a couple of options for making this work (including Lanorkin's response below), but I'd really like to know why this is happening. Am I doing something wrong or is there a bug in Moq or Visual Studio that I should be submitting?

Update: I ended up going with a version of Denys solution below and filing a bug report to Moq. My setup now looks like:

mockMyType1.Setup(m => m.Equals(It.Is<MyType>(x => ReferenceEquals(x, mockMyType1.Object)))).Returns(true);
like image 231
rpmcnally Avatar asked Apr 01 '13 15:04

rpmcnally


1 Answers

Yes, mocking Equals(object) make it fail (use Reflector/dotPeek to see more):

MOQ StackOverflow

Good news - it's easy to workaround. Just add Equals overload to MyType class, thus mocking Equals(MyType) instead of Equals(object):

    public virtual bool Equals(MyType obj)
    {
        return Equals((object)obj);
    }
like image 131
Lanorkin Avatar answered Sep 24 '22 08:09

Lanorkin