The Inquisitive Coder – Davy Brion's Blog

Trying to walk that thin line between intelligence and ignorance

The Tests For The Readable Code Challenge

Posted by Davy Brion on February 22nd, 2009

After the uncommented code, and then the commented version of the code, you finally get to see the tests that verify that solution protects the code from the issue it was facing. I think all 3 posts (and the comments on them) sufficiently explain the problem and the solution so i won’t go through the trouble of explaining everything in this post. The tests however, might not be very clear to everyone. I’m only posting 3 tests, though there are more but then the post would just be way too long.

These tests use the following 2 fields:

        private Broadcaster broadcaster;

        private IClientProxyFactory clientFactory;

Which are set up before each test like this:

            clientFactory = MockRepository.GenerateMock<IClientProxyFactory>();

            broadcaster = new Broadcaster(clientFactory);

First of all, take a look at some of the utility methods that these tests use:

        private List<IClientProxy> GetBroadcastersClients()

        {

            var clientsFieldInfo = typeof(Broadcaster).GetField("clients", BindingFlags.NonPublic | BindingFlags.Instance);

            return (List<IClientProxy>)clientsFieldInfo.GetValue(broadcaster);

        }


        private Exception GetExceptionThrownBy(Action yourCode)

        {

            try { yourCode(); } catch (Exception e) { return e; }

            return null;

        }

 

        private void RegisterClientWithBroadcaster(IClientProxy client)

        {

            clientFactory.Stub(f => f.CreateClientProxyForCurrentContext(null))

                .IgnoreArguments().Return(client).Repeat.Once();

 

            broadcaster.Register();

        }

 

        private IClientProxy RegisterClientWithImplementationForSend(Action implementation)

        {

            var client = MockRepository.GenerateMock<IClientProxy>();

 

            client.Stub(c => c.SendNotificationAsynchronously(null))

                .IgnoreArguments().WhenCalled(obj => implementation());

 

            RegisterClientWithBroadcaster(client);

 

            return client;

        }

 

        private IClientProxy RegisterClientWithEmptySendImplementation()

        {

            return RegisterClientWithImplementationForSend(() => { });

        }

 

        private void RegisterClientsWithImplementationForSend(int number, Action implementation)

        {

            var clients = new IClientProxy[number];

 

            for (int i = 0; i < number; i++)

            {

                clients[i] = RegisterClientWithImplementationForSend(implementation);

            }

        }

And then the actual tests:

        [Test]

        public void RegisterClientWhileBroadcasting_ClientIsAddedAndBroadcastingDidntThrowException()

        {

            RegisterClientsWithImplementationForSend(5, () => Thread.Sleep(50));

 

            Exception exceptionFromBroadcastThread = null;

            var broadcastThread =

                new Thread(() => exceptionFromBroadcastThread = GetExceptionThrownBy(() => broadcaster.Broadcast(null)));

 

            broadcastThread.Start();

            Thread.Sleep(50);

 

            var newClient = RegisterClientWithEmptySendImplementation();

 

            broadcastThread.Join();

 

            Assert.IsNull(exceptionFromBroadcastThread);

            Assert.That(GetBroadcastersClients().Contains(newClient));

        }

 

        [Test]

        public void ClientFaultedWhileBroadcasting_FaultedClientIsRemovedFromClientsList()

        {

            RegisterClientsWithImplementationForSend(2, () => { });

 

            var faultyClient = MockRepository.GenerateMock<IClientProxy>();

 

            faultyClient.Stub(c => c.SendNotificationAsynchronously(null))

                .IgnoreArguments().WhenCalled(obj => faultyClient.Raise(c => c.Faulted += null, faultyClient, EventArgs.Empty));

 

            RegisterClientWithBroadcaster(faultyClient);

            RegisterClientsWithImplementationForSend(2, () => { });

 

            broadcaster.Broadcast(null);

 

            Assert.IsFalse(GetBroadcastersClients().Contains(faultyClient));

        }

 

        [Test]

        public void ClientFaultedInSeparateThreadWhileBroadcasting_FaultedClientIsRemovedWithoutExceptionDuringBroadcasting()

        {

            var faultyClient = RegisterClientWithEmptySendImplementation();

            RegisterClientsWithImplementationForSend(10, () => Thread.Sleep(50));

 

            Exception exceptionFromBroadcastThread = null;

            var broadcastThread =

                new Thread(() => exceptionFromBroadcastThread = GetExceptionThrownBy(() => broadcaster.Broadcast(null)));

            broadcastThread.Start();

            Thread.Sleep(150);

 

            faultyClient.Raise(c => c.Faulted += null, faultyClient, EventArgs.Empty);

 

            broadcastThread.Join();

 

            Assert.IsNull(exceptionFromBroadcastThread);

            Assert.IsFalse(GetBroadcastersClients().Contains(faultyClient));

        }

Note: i’m not sure if this is actually the best way to test this code… there will probably be better solutions for testing threading issues.

2 Responses to “The Tests For The Readable Code Challenge”

  1. Peter Morris Says:

    When I want to invoke something at a specific time in a thread I create a ManualResetEvent and have my thread wait for that, I then set everything up and set the event to wake up the thread.

    I found this particularly good for testing race conditions, because I was able to sleep the thread at a specific point (updating the DB).

    http://mrpmorris.blogspot.com/2008/10/implementing-complex-unit-testing-with.html

  2. Dew Drop - February 23, 2009 | Alvin Ashcraft's Morning Dew Says:

    [...] The Tests For The Readable Code Challenge (Davy Brion) [...]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>