Code Injection and Legacy Code

What's the best way of making the minimum changes to legacy code so you can test it?

SO. You're lumbered into maintaining some old production code. It desperately needs refactoring, but you're in an environment where refactoring tasks are part of a project plan..."refactoring is seen as tinkering, and you might break something..."

You know you need to test. The old code performs a slow database query halfway through a vital method that your highly suspicious of. The database query is fine. It's trivial and is used elsewhere.

How do you stub out the slow code and inject a mock?

What's the best way of making the minimum of changes to the code, and placating the permies at the same time?

Here's my solution...

The Old Code

Here's the old code. A unit test has been grafted in, highlighted in bold. It's a start, but it runs dog slow.

using System.Collections.Generic;

using System.Threading;

using NUnit.Framework;

 

namespace InjectionClassLibrary1

{   

    public class SuperAdderAnOldLegacyClass

    {

        private readonly int _portNumber;

 

        public SuperAdderAnOldLegacyClass(int portNumber)

        {

            _portNumber = portNumber;

        }

 

        public int DoAdd(List<int> l)

        {

            var ret = 0;

 

            // stuff happens

 

            ret += DoSum(l);

 

            // more stuff happens

 

            return ret;

        }

 

        private int DoSum(List<int> l)

        {

            var ret = 0;

            foreach (int i in l)

            {

                ret += SlowSQLQuery(i);

            }

            return ret;

        }

 

        private int SlowSQLQuery(int i )

        {

            Thread.Sleep(1000 + _portNumber/1000);

            return i;

        }

    }

 

    [TestFixture]

    public class Container

    {

        [Test]

        public void OriginalImplemmentation()

        {

            var c = new SuperAdderAnOldLegacyClass(8080);

            int sum = c.DoAdd(new List<int> { 1, 2, 3 });

            Assert.AreEqual(sum, 6);

        }

    }

}



The New Code

Minimum impact code has been grafted in, highlighted in bold.

The FastTest method runs in a fraction of a second! The permies are happy: there is only 1 lines of production code  changed. Their valuable legacy code has survived virtually unscathed by the machinations of the money-grabbing mercenary contractor.

 

using System.Collections.Generic;

using System.Threading;

using NUnit.Framework;

 

namespace InjectionClassLibrary1

{

    public class AdderAnOldLegacyClass

    {

        private readonly int _portNumber;

 

        public AdderAnOldLegacyClass(int portNumber)

        {

            _portNumber = portNumber;

        }

 

        public int DoAdd(List<int> l)

        {

            var ret = 0;

 

            // stuff happens

 

            ret += DoSum(l);

 

            // more stuff happens

 

            return ret;

        }

 

        protected virtual int DoSum(List<int> l)

        {

            var ret = 0;

            foreach (int i in l)

            {

                ret += SlowSQLQuery(i);

            }

            return ret;

        }

 

        private int SlowSQLQuery(int i)

        {

            Thread.Sleep(1000 + _portNumber / 1000);

            return i;

        }

    }

   

    [TestFixture]

    public class Container

    {

        public class SuperAdderMerelyForTesting : AdderAnOldLegacyClass

        {

            public SuperAdderMerelyForTesting(int portNumber) : base(portNumber)

            {

            }

 

            protected override int DoSum(List<int> l)

            {

                var ret = 0;

                foreach (var i in l)

                {

                    ret += i;

                }

                return ret;

            }

        }

 

   

        [Test]

        public void FastTest()

        {

            var c = new SuperAdderMerelyForTesting(8080);

            int sumMock = c.DoAdd(new List<int> { 1, 2, 3 });

            Assert.AreEqual(sumMock, 6);

        }

    }

}