views:

27

answers:

1

I'm trying to write a unit test that will raise an event on a mock object which my test class is bound to.

What I'm keen to test though is that when my test class gets its eventhandler called, it should only call a method on certain values of the eventhandler's parameters.

My test seems to pass even if I comment the code that calls ProcessPriceUpdate(price);

I'm in VS2005 so no lambdas please :(

So...

public delegate void PriceUpdateEventHandler(decimal price);

public interface IPriceInterface{
    event PriceUpdateEventHandler PriceUpdate;
}

public class TestClass
{
    IPriceInterface priceInterface = null;

    TestClass(IPriceInterface priceInterface)
    {
        this.priceInterface = priceInterface;
    }

    public void Init()
    {
        priceInterface.PriceUpdate += OnPriceUpdate;
    }

    public void OnPriceUpdate(decimal price)
    {
        if(price > 0)
           ProcessPriceUpdate(price);
        }

    public void ProcessPriceUpdate(decimal price)
    {
        //do something with price
    }
}

And my test so far... :s

public void PriceUpdateEvent()
    {
        MockRepository mock = new MockRepository();
        IPriceInterface pi = mock.DynamicMock<IPriceInterface>();
        TestClass test = new TestClass(pi);

        decimal prc = 1M;

        IEventRaiser raiser;

        using (mock.Record())
        {
            pi.PriceUpdate += null;

            raiser = LastCall.IgnoreArguments().GetEventRaiser();

            Expect.Call(delegate { test.ProcessPriceUpdate(prc); }).Repeat.Once();

        }
        using (mock.Playback())
        {
            test.Init();
            raiser.Raise(prc);
        }
    }
A: 

I will usually break this kind of thing into at least two tests. The first verifies that triggering the event calls the appropriate callback (and that callback is ALWAYS called, no conditions). The conditional logic you were trying to test, that goes into the appropriate callback, which is tested by additional separate tests.

The first test can be implemented by creating a derived class from the class under test, with the appropriate callback overriden to simply record that it was called successfully. Then when you trigger the event, you can verify the callback is called.

Next step is to test the callback method directly, as you would any other method.

Here's a skeleton test with the validation code you'd need for the first test. Note that OnPriceUpdate would be made virtual in TestClass:

public class TestClass_verifiesCallback : TestClass
{
    public bool WasCallbackCalled = false;
    public decimal PricePassedToCallback = 0;

    public override void OnPriceUpdate(decimal price)
    {
        WasCallbackCalled = true;
        pricePassedToCallback = price;
    }
}

... test methods

public TestInitSetsPriceUpdateCallback()
{
   .. setup

   var sut = new TestClass_verifiesCallback()

   .. run test

   // verification:
   Assert.IsTrue(sut.WasCallbackCalled);
   Assert.AreEqual(expectedValue, sut.PricePassedToCallback);
}

Your later tests can test OnPriceUpdate directly.

Frank Schwieterman
Any chance of a a bit of code to illustrate. I think I get what you're saying but a dash of code would really help. :)
MattC