Stand by...

How to test main()?

When you are doing Test-Driven Development you try to test whatever you wrote. It is even better! You write tests before you write any line of code. But eventually when you have your brand new functions and classes (all 100% covered by tests) you have to integrate it in some working software. In the very end you have to write main(int, char**) function. How do you test it using Unit Tests?

Imagine that you have such easy (well known) application:

#include <iostream>

int main(int argc, char** argv)
{
    std::cout << "Hello World!" << std::endl;
    std::cout << "Number of arguments: " << argc << std::endl;
}

How would you test it using UnitTests? The easiest answer is that you cannot test it because there are no seam points which allow testing. It’s all true but I would like to show you that main() is testable… maybe not directly but you may transform above code with only little effort to something testable. For example you can do something like this:

#include <iostream>

class Main
{
public:
    static int main(int argc, char** argv)
    {
        std::cout << "Hello World!" << std::endl;
        std::cout << "Number of arguments: " << argc << std::endl;
        return 0;
    }
};

int main(int argc, char** argv)
{
    return Main::main(argc, argv);
}

It is much better now, isn’t it! At least we can call our main function in our tests! Unfortunately there are still some problems which will make testing of this a little pain. Our brand new Main::main function calls global objects which are always trouble for Unit Tests. But this also could be solved!

#include <iostream>

class Main
{
public:
    Main(std::ostream& output) : output(output) {}

    int main(int argc, char** argv)
    {
        output << "Hello World!" << std::endl;
        output << "Number of arguments: " << argc << std::endl;
        return 0;
    }

private:
    std::ostream& output;
};

int main(int argc, char** argv)
{
    Main app_main(std::cout);
    return app_main.main(argc, argv);
}

What we achieve is class Main which can be freely instantiate in any test we want. We could inject any kind of std::ostream to it (ie. std::stringstream) and test what was written to it. We may also manipulate with two arguments to check correct and invalid argument values. All of this is possible right now.

For those worrying about performance – modern compilers should compile our new code to the same binary as it would do for our previous version,  so don’t worry!

Happy testing!

0 Comment(s). Add a comment or Trackback

Leave a comment ↓

Welcome back, (change)

submitting...