Introduction: EventTester with expression trees

I always wanted to get my hands dirty with a little expression tree magic but never had the time to do so. When test driving code of a component you are currently working on you might feel in the middle of the “Do a little change, let it fail, make it green” process that your component needs an event which is publicly visible and can be subscribed by clients. But how would you test that the event is fired on your component’s interface? I’ll show you how this is normally achieved and how an event tester could simplify the process.

Consider the following component:

        public class Component
        {
            public event EventHandler Started;

            public event EventHandler<CancelEventArgs> Stopping;

            public event EventHandler<ComponentStoppedEventArgs> Stopped;

            public void Start()
            {
                if (this.Started != null)
                {
                    this.Started(this, EventArgs.Empty);
                }
            }

            public void Stop()
            {
                if (this.Stopping != null)
                {
                    CancelEventArgs cancelEventArgs = new CancelEventArgs();
                    this.Stopping(this, cancelEventArgs);

                    if (this.Stopped != null && IsNotCanceled(cancelEventArgs))
                    {
                        this.Stopped(this, new ComponentStoppedEventArgs(this));
                    }
                }
            }

            private static bool IsNotCanceled(CancelEventArgs cancelEventArgs)
            {
                return !cancelEventArgs.Cancel;
            }
        }

And the corresponding custom event arguments:

        public class ComponentStoppedEventArgs : EventArgs
        {
            public ComponentStoppedEventArgs(Component component)
            {
                this.StoppedComponent = component;
            }

            public Component StoppedComponent { get; private set; }
        }

The component does nothing more than fire a Started event when the client calls Start() and when the client calls Stop() the component fires an event which can be canceled therefore allowing to interrupt the stop process. When the stop process is not canceled the Stopped event is fired. Normally we would have tested our code like the following (skeleton code):

        [Test]
        public void StartingTheComponentMustFireTheStartedEvent()
        {
            AutoResetEvent startedEvent = new AutoResetEvent(false);

            var testee = new Component();
            testee.Started += (sender, e) => startedEvent.Set();

            testee.Start();

            Assert.IsTrue(startedEvent.WaitOne(500), "The component's started event was not fired!");
        }

This approach is really handy when dealing with events on your class under test. But what happens when an event on your component needs to be fired multiple times or even multiple times with different event arguments which should be checked in your unit tests if they contain the correct data or the number of fired events should be counted? The above test code is prone to get quickly quite complex and not really easy to maintain. That’s when the event tester kicks in. To make you curious for my next article I want to show you how the above test code could be written with the event tester that we are going to build together:

        [Test]
        public void StartingTheComponentMustFireTheStartedEventWithAutoAttachEventTester()
        {
            const int EventMustBeFiredExactlyOneTime = 1;

            var testee = new Component();
            var eventTester = new AutoAttachEventTester<EventArgs>(testee, "Started");

            testee.Start();

            Assert.AreEqual(EventMustBeFiredExactlyOneTime, eventTester.FireCounter, "The component's started event was not fired!");
        }

        [Test]
        public void StartingTheComponentMustFireTheStartedEventWithEventTester()
        {
            const int EventMustBeFiredExactlyOneTime = 1;

            var testee = new Component();
            var eventTester = new EventTester<EventArgs>(testee, "Started");
            testee.Started += eventTester;

            testee.Start();

            Assert.AreEqual(EventMustBeFiredExactlyOneTime, eventTester.FireCounter, "The component's started event was not fired!");
        }

About the author

Daniel Marbach

1 comment

By Daniel Marbach

Recent Posts