DevPinoy.org
A Filipino Developers Community

>>> First two to make 3 wins! <<<

Using NMock to test interaction of IComparable objects with it's IComparer
I have a requirement to sort a business object and obviously providing an IComparer for the said business object and implementing IComparable is the way to do it.  And because of the dependency of the business object to the IComparer, i thought this could be a perfect way to use NMock for the first time (after seeing cruizer's previous post here).

Let's take a Person Class with an integer Age property.  The main logic for comparison is to use the Age for comparing Person instances.  And since the Person class depends on a PersonComparer, we can inject it to the Person's constructor for the test methods to inject the mocked IComparer instance (although ideally, there should be one instance of IComparer for a business object so they should be designed as static, for simplicity Stick out tongue, i'll use an instance field IComparer for the Person class).

public class Person : IComparable

{

    IComparer _comparer;

 

    public Person()

    {

        _comparer = new PersonComparer();

    }

 

    public Person(IComparer comparer)

    {

        _comparer = comparer;

    }

 

 

    private int _age = 0;

 

    public int Age

    {

        get { return _age; }

        set { _age = value; }

    }

 

    public int CompareTo(object obj)

    {

        return _comparer.Compare(this, obj);

    }

}

 

public class PersonComparer : IComparer

{

    int IComparer.Compare(object x, object y)

    {

        Person left = x as Person;

        Person right = y as Person;

        if (left != null && right != null)

        {

            return left.Age.CompareTo(right.Age);

        }

        throw new ArgumentException("Comparison should be between Person instances");

    }

}

 

[TestFixture]

public class PersonTests

{

    [Test]

    public void CompareTo_DelagatesCallToIComparerCompare()

    {

        Mockery mockery = new Mockery();

        IComparer comparer = mockery.NewMock<IComparer>();

        Person person = new Person(comparer);

        Expect.Once.On(comparer).Method("Compare").With(person, person).Will(Return.Value(0));

        int i = person.CompareTo(person);

        mockery.VerifyAllExpectationsHaveBeenMet();

    }

}


I previously encountered a RemotingException (System.Runtime.Remoting.RemotingException : ByRef value type parameter cannot be null) and later found out that i had the wrong construct (ignoring the return value of the call to Compare method by the expectation).  My initial expectation setup was:

Expect.Once.On(comparer).Method("Compare").With(person, person);



I haven't really read the docs but just took my first stab on using NMock.

It will be helpful if NMock shipped with it's intellisense (xml) file so i don't have to consult the docs.

Posted 09-19-2006 12:25 PM by jokiz
Filed under: ,

Comments

jop wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-18-2006 10:50 PM
Here's a challenge: can you write the test WITHOUT using a mock?
cruizer wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-18-2006 11:56 PM
without using a mock, you will have to create your own MockPersonComparer which, say, would implement IComparer. Then you'll have to put in code in the Compare() method to signal that the method is indeed being called (and, say, called only once). e.g. public class MockPersonComparer : IComparer { public int callCount = 0; int Compare(object x, object y) { callCount++; Person left = x as Person; Person right = y as Person; if (left != null && right != null) { return left.Age.CompareTo(right.Age); } throw new ArgumentException("Comparison should be between Person instances"); } } so you'll use MockPersonComparer in your NUnit test method. then you can just later on: (in CompareTo_DelagatesCallToIComparerCompare) MockPersonComparer comparer = new MockPersonComparer(); Person person = new Person(comparer); int i = person.CompareTo(person); Assert.AreEqual(1, comparer.CallCount); Assert.AreEqual(0, i); or something like that :)
jop wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-19-2006 12:11 AM
Why not let PersonTests implement IComparer? Then you can just pass in the current "this" when creating the person: new Person(this).
cruizer wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-19-2006 12:19 AM
ngak!!! my code looks ugly!!! :P
cruizer wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-19-2006 12:52 AM
oo nga no? your idea makes better sense, jop.
jop wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-19-2006 2:14 AM
Thanks, but the idea was not originally mine. I stole it from Kent Beck's `TDD by Example' :-P. He called at a Self Shunt. It is one type of stub or test dummy that can considered as a lightweight Mock object (or are mock objects are heavyweight stubs?). I reserve mocks if and only if using a stub is more work. Most of the times that occurs only on classes that are not designed using TDD. I also use mocks on tests involving domain boundaries - UI layer, DAL, Infrastructure, etc.
Ron Wildman wrote re: Using NMock to test interaction of IComparable objects with it's IComparer
on 09-19-2006 10:59 PM
of course this wont work if you have a static Compare. For that you would need to use the heavy guns like TypeMock.NET http://www.typemock.com

Copyright DevPinoy 2005-2008