The official Fatica Labs Blog! RSS 2.0
# Wednesday, February 29, 2012

In this post I will show how to make testable something that ( at least me ) usually left as untested. I’m talking about the preparing phase of a console app, the checking arguments error reporting and so on. That logic is usually so simple that any good cow boy programmer would probably leave outside any unit testing. Unfortunately we should at least do some manually check that prove that logic working, and doing things manually is always silly. In this post we assume we have a working command line parsing library, and a mocking framework. Let see the cowboy code:

        static void Main(string[] args)
        {
            string optA,optB;
            optA = optB = null;
            bool done = false;
            OptionSet set = new OptionSet();
            set.Add("a=", (k) => optA = k);
            set.Add("b=", (k) => optB = k);
            set.Add("h", (k) => { LongHelp(); done = true; });
            set.Parse(args);
            if (done)
                return;
            if (string.IsNullOrEmpty(optA) || string.IsNullOrEmpty(optB))
            {
                ShortHelp();
                return;
            }
            DoTheJob(optA,optB);
            
        }

        private static void DoTheJob(string optA, string optB)
        {
            //something interesting here
        }

        private static void LongHelp()
        {
            Console.Error.WriteLine("Long help here...");
        }

        private static void ShortHelp()
        {
            Console.Error.WriteLine("Short help here");
        }
    }

So nothing special, the example is actually very simple, we have two mandatory parameters, a command line switch to print a long help. If one argument is missing a short help line must be presented. If all the parameters are provided, the DoTheJob() method should be called with the correct values.

Current code is not testable without hosting the console application as a process, and looking at the stdout to see what happen. Even by this strategy, we can not punctually check what is passed to DoTheJob. So we want to refactor the code, without adding any complexity to the app. So here below the proposed refactoring:

    public class Program
    {
        static void Main(string[] args)
        {
            new Program().Run(args);
        }
        public virtual void Run(string[] args)
        {
            string optA, optB;
            optA = optB = null;
            bool done = false;
            OptionSet set = new OptionSet();
            set.Add("a=", (k) => optA = k);
            set.Add("b=", (k) => optB = k);
            set.Add("h", (k) => { LongHelp(); done = true; });
            set.Parse(args);
            if (done)
                return;
            if (string.IsNullOrEmpty(optA) || string.IsNullOrEmpty(optB))
            {
                ShortHelp();
                return;
            }
            DoTheJob(optA, optB);

        }

        public virtual void DoTheJob(string optA, string optB)
        {
            //something interesting here
        }

        public virtual void LongHelp()
        {
            Console.Error.WriteLine("Long help here...");
        }

        public virtual void ShortHelp()
        {
            Console.Error.WriteLine("Short help here");
        }
    }

 

So pretty easy, we provide a non static method Run(), and all the internal function are declared virtual. This is a five minutes modification we could probably apply to any other code like this we have. The difference is that we can write some unit test, lets see how:

        [TestMethod]
        public void ShouldDisplayShortHelp()
        {
            var moq = new Mock();
            moq.CallBase = true;
            moq.Setup(k=>k.DoTheJob(It.IsAny(),It.IsAny()))
                .Throws(new InvalidProgramException("Should not call"));
            moq.Object.Run(new string[0]);
            moq.Verify(k => k.ShortHelp());
        }
        [TestMethod]
        public void ShouldDisplayLongHelp()
        {
            var moq = new Mock();
            moq.CallBase = true;
            moq.Setup(k => k.DoTheJob(It.IsAny(), It.IsAny()))
                .Throws(new InvalidProgramException("Should not call"));
            moq.Object.Run(new string[]{"-h"});
            moq.Verify(k => k.LongHelp());
        }
        [TestMethod]
        public void ShouldInvokeWithProperParameters()
        {
            var moq = new Mock();
            moq.CallBase = true;
            moq.Setup(k => k.DoTheJob("p1", "p2")).Verifiable();
            moq.Object.Run(new string[] { "-a=p1","-b=p2" });
            moq.Verify();
        }

 

I used the MoQ library, please note the Callbase set to true, because we are using the same object for driving and for expect calls. So in conclusion, we achieve a real unit test of something we sometimes left apart, we did that in memory, and even if the example is really trivial, the concept can be used in complex scenarios too. What about testing the inside part of DoTheJob()? well, if a good testing strategy is used, the internal part should be testable outside somewhere else, here we are  proving we can test the shell. 

Wednesday, February 29, 2012 9:47:36 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
CodeProject | CSharp | Programmin

My Stack Overflow
Contacts

Send mail to the author(s) E-mail

Tags
profile for Felice Pollano at Stack Overflow, Q&A for professional and enthusiast programmers
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2014
Felice Pollano
Sign In
Statistics
Total Posts: 157
This Year: 0
This Month: 0
This Week: 0
Comments: 123
This blog visits
All Content © 2014, Felice Pollano
DasBlog theme 'Business' created by Christoph De Baene (delarou) and modified by Felice Pollano