Object Oriented, Test Driven Design in C# and Java: A Practical Example Part #4

Download the code in C#
Download the code in Java

Check out my interview on .NET Rocks! – TDD on .NET and Java with Paul Mooney

For a brief overview, please refer to this post.

That’s the hard work done! Our WorkerDrones can now deliver RobotParts to their respective FactoryRoom implementations. Now, we can start building Robots! But wait…

Oh, no. Something's gone wrong!

“Oh, no. Something’s gone horribly wrong!”

It looks like our code is broken. Remember our WorkerDrone logic?

C#

        public void IdentifyRobotPart(RobotPart robotPart) {
            switch (robotPart.RobotPartCategory) {
                case RobotPartCategory.Assembly:
                    _transportMechanism = new AssemblyRoomTransportMechanism();
                    break;
                case RobotPartCategory.Weapon:
                    _transportMechanism = new ArmouryTransportMechanism();
                    break;
            }
        }

Java

    public void identifyRobotPart(robotPart robotPart) {
        switch (robotPart.getRobotPartCategory()) {
            case assembly:
                _transportMechanism = new assemblyRoomTransportMechanism();
                break;
            case weapon:
                _transportMechanism = new armouryTransportMechanism();
                break;
        }
    }

Our Unit Tests only ever considered WorkerDrones that transport a single RobotPart at a time. We haven’t considered the consequences of transporting multiple RobotParts.

As it turns out, our WorkerDrone's TransportMechanism will be overwritten every time a RobotPart is picked up. This will produce incorrect behaviour; essentially, all RobotParts held by a WorkerDrone will be delivered to the same FactoryRoom implementation – the FactoryRoom implementation associated with the last RobotPart to be picked up, which will overwrite the previous RobotPart that was picked up.

“How do we fix this?”

Well, currently our WorkerDrones can only successfully transport a single RobotPart at a time. Our Factory would operate a lot more efficiently if our WorkerDrones could carry multiple RobotParts and successfully deliver them without having to return to the DeliveryBay after each run.

More than 1 RobotPart at a time? Please! Easy work for me!!!

More than 1 RobotPart at a time? Please! Easy work for me!!!

First, let’s change the IdentifyRobotPart method so that it simply returns a TransportMechanism implementation based on the RobotPart parameter:

C#

        public TransportMechanism IdentifyRobotPart(RobotPart robotPart) {
            switch (robotPart.RobotPartCategory) {
                case RobotPartCategory.Assembly:
                    return new AssemblyRoomTransportMechanism((Assembly) robotPart);
                case RobotPartCategory.Weapon:
                    return new ArmouryTransportMechanism((Weapon) robotPart);
            }
            throw new NotImplementedException("I can't identify this component!");
        }

Java

    public transportMechanism identifyRobotPart(robotPart robotPart) throws UnsupportedOperationException {
        switch (robotPart.getRobotPartCategory()) {
            case assembly:
                return new assemblyRoomTransportMechanism((assembly) robotPart);
            case weapon:
                return new armouryTransportMechanism((weapon) robotPart);
        }
        throw new UnsupportedOperationException("I can't identify this component!");
    }

We’ll call this method every time our WorkerDrone picks up a RobotPart. Next, let’s replace our TransportMechanism member-variable with a collection:

C#

    private readonly List<TransportMechanism> _transportMechanisms;

Java

    private List<transportMechanism> _transportMechanisms;

Now we need to modify the OffLoadRobotPart to simply transfer the RobotPart that we just picked up to its associated FactoryRoom instance.

C#

        public FactoryRoom OffLoadRobotPart() {
            if (_factoryRoom == null) {
                EnterRoom();
            }
            _factoryRoom.AddRobotPart(_robotPart);
            return _factoryRoom;
        }

Java

    public E offLoadRobotPart() {
        if (_factoryRoom == null) {
            enterRoom();
        }

        _factoryRoom.addRobotPart(_robotPart);
        return _factoryRoom;
    }

Note that we’ve also changed our TransportMechanism abstraction to accept a RobotPart by default. This is where we’ll load the RobotPart that is picked up by the WorkerDrone.

C#

        protected TransportMechanism(RobotPart robotPart) {
            _robotPart = robotPart;
        }

Java

    protected transportMechanism(U robotPart) {
        _robotPart = robotPart;
    }

Now, the most important part. We need to change the TransportRobotParts method to loop through each TransportMechanism (we’ll have 1 for each RobotPart that we picked up) and execute the OffLoadRobotPart method:

C#

       public void TransportRobotParts() {
            foreach (var transportMechanism in _transportMechanisms) {
                transportMechanism.OffLoadRobotPart();
            }

            _transportMechanisms.Clear();
        }

Java

   public void transportRobotParts() {
        for (Iterator<transportMechanism> i = _transportMechanisms.iterator(); i.hasNext(); ) {
            transportMechanism transportMechanism = i.next();
            transportMechanism.offLoadRobotPart();
        }

        _transportMechanisms.clear();
    }

OK. Now our WorkerDrone can successfully deliver multiple RobotParts to multiple FactoryRooms. Now we need to ensure that it will return to the DeliveryBay once it has delivered its payload.

I'm ready to transport more RobotParts! Back to the DeliveryBay I go...

“I’m ready to transport more RobotParts! Back to the DeliveryBay I go…”

AS usual with TDD, let’s start with the tests, and introduce a new test to assert that multiple RobotParts can be delivered successfully. Our test will cover a scenario where a WorkerDrone delivers multiple RobotParts and then returns to the DeliveryBay.

C#

        public void WorkerDroneReturnsToDeliveryBayAfterDeliveringRobotParts() {
            WorkerDrone workerDrone = new MockedWorkerDrone();

            var randomAssembly = new MockedAssembly();
            var randomWeapon = new MockedWeapon();

            workerDrone.PickUpRobotPart(randomAssembly);
            workerDrone.PickUpRobotPart(randomWeapon);

            workerDrone.TransportRobotParts();
            Assert.True(workerDrone.GetTransportationMechanisms().Any());

            var transportMechanism = workerDrone.GetTransportationMechanisms().First();
            Assert.IsInstanceOf<DeliveryBayTransportMechanism>(transportMechanism);
        }

Java

    public void workerDroneReturnsToDeliveryBayAfterDeliveringRobotParts() {
        workerDrone workerDrone = new mockedWorkerDrone();

        robotPart randomAssembly = new mockedAssembly();
        robotPart randomWeapon = new mockedWeapon();

        workerDrone.pickUpRobotPart(randomAssembly);
        workerDrone.pickUpRobotPart(randomWeapon);

        workerDrone.transportRobotParts();

        Iterator<transportMechanism> iterator = workerDrone.getTransportMechanisms().iterator();
        assertTrue(iterator.hasNext());

        transportMechanism transportMechanism = iterator.next();
        assertThat(transportMechanism, instanceOf(deliveryBayTransportMechanism.class));
    }

Notice here that we assert that our WorkerDrone contains a single DeliveryBayTransportMechanism. This implementation, when executed, simply returns the WorkerDrone to the DeliveryBay. Let’s look at how this works:

C#

        public void TransportRobotParts() {
            foreach (var transportMechanism in _transportMechanisms) {
                transportMechanism.OffLoadRobotPart();
            }

            _transportMechanisms.Clear();

            var deliveryBayTransportMechanism = new DeliveryBayTransportMechanism();
            _transportMechanisms.Add(deliveryBayTransportMechanism);

            deliveryBayTransportMechanism.EnterRoom();
        }

Java

    public void transportRobotParts() {
        for (Iterator<transportMechanism> i = _transportMechanisms.iterator(); i.hasNext(); ) {
            transportMechanism transportMechanism = i.next();
            transportMechanism.offLoadRobotPart();
        }

        _transportMechanisms.clear();

        deliveryBayTransportMechanism deliveryBayTransportMechanism = new deliveryBayTransportMechanism();
        _transportMechanisms.add(deliveryBayTransportMechanism);

        deliveryBayTransportMechanism.enterRoom();
    }

Note that we explicitly create a DeliveryBayTransportMechanism instance and execute the enterRoom method. Now our WorkerDrone has returned to DeliveryBay after successful delivery of its payload. We’ve demonstrated how TDD and OOD can facilitate change during the software development life-cycle.

The next tutorial in the series will focus on building Robots.

Connect with me:

RSSGitHubTwitter
LinkedInYouTubeGoogle+

1 thought on “Object Oriented, Test Driven Design in C# and Java: A Practical Example Part #4

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s