Using std::function to make unit testing easier in C/C++ systems

If your day job is in a brown field C/C++ system, you can sometimes feel a little unloved. On the one hand, the Java guys seem to have all of these cool libraries for enterprise software. On the other hand, you have the web guys with their javascript (“hyyyyyyypeeee”). Finally, you have all of these “high productivity” high-level gluing languages like python.

Luckily, C++ has plenty of tools and lots of exciting things going on in the language. So it can definitely hold its own. Unfortunately, C/C++ shops can sometimes be a little slow to catch on. This is partly because you have a fair amount of existing code base which was written before all of this cool stuff was dreamt up.

In particular, a London-school (mocking) approach to TDD can be quite hard, when a large part of your codebase is ruled by various super-functions which execute lots of other functions. Those other functions may access the database, some other server etc. etc. Here, dependency injection and mocking isolation without a big refactor has traditionally not been very easy.

Say, e.g. you have a function that you want to test, but it calls another function which deals with database interaction, global memory, a request to a web service or something else:

Header file declaration

extern Project365::Widget ProductionCodeLoadWidget(const std::string& rstrWidgetRef);

Cpp file definition

extern Project365::Widget ProductionCodeLoadWidget(const std::string& rstrWidgetRef)
  {
  if (rstrWidgetRef.find(“Database”) != std::string::npos)
    {
    return LoadWidgetFromDatabase(rstrWidgetRef);
    }
  else if (rstrWidgetRef.find(“Web Request”) != std::string::npos)
    {
    return LoadWidgetFromWebRequest(rstrWidgetRef);
    }
  else
    {
    return LoadWidgetFromMemory(rstrWidgetRef);
    }
  }

If this function had been a member of the interface of an object, you would have delegated the function call inside of the interface to another member object in a strategy pattern. To unit test, you would then have mocked that object and passed it in as part of the constructor:

Project365::Widget WidgetLoader::Load(const std::string& rstrWidgetRef)
  {
  if (rstrWidgetRef.find(“Database”) != std::string::npos)
    {
    return m_pdbLoader->Load(rstrWidgetRef);
    }
  else if (rstrWidgetRef.find(“Web Request”) != std::string::npos)
    {
    return m_pwebLoader->Load( (rstrWidgetRef);
    }
  else
    {
    return m_pmemoryLoader->Load(rstrWidgetRef);
    }
  }

WidgetLoader::WidgetLoader(IDatabaseLoader* pdbLoader, IWebLoader* pwebLoader, IMemoryLoader* pmemoryLoader)
: m_pdbLoader(dbLoader), m_pwebLoader(pwebLoader), m_pmemoryLoader(pmemoryLoader) {}

This kind of change would isolate the particular function you want to test. However, it is also a fair amount of effort with some potentially intrusive refactoring – especially if you then want to make sure that your object’s overall responsibilities are coherent and not just a transformation of this function. (To get this to work, you would probably want to use the technique described in “Growing object-oriented software guided by tests”: You’d have an acceptance test layer which seals a larger section of code and so enables this bigger refactoring at smallish risk).

The following is a “little refactor” alternative which enables you to get some initial unit testing coverage so that you can be more confident if you are looking for a larger refactor later on: The essence of it is to supply a std::function object to the function with a default argument of the function which you want to call in production. 

Right, so what does that mean in code. You’d change the function in production code to look something like the following:

Header file declaration

extern Project365::Widget ProductionCodeLoadWidget(const std::string& rstrWidgetRef,
                          std::function<Project365::Widget(const std::string&)> loadWidgetFromDatabase = LoadWidgetFromDatabase,
                          std::function<Project365::Widget(const std::string&)> loadWidgetFromMemory = LoadWidgetFromMemory,
                          std::function<Project365::Widget(const std::string&)> loadWidgetFromWebRequest = LoadWidgetFromWebRequest);

Cpp file definition

extern Project365::Widget ProductionCodeLoadWidget(const std::string& rstrWidgetRef,
                                                         std::function<Project365::Widget(const std::string&)> loadWidgetFromDatabase,
                                                         std::function<Project365::Widget(const std::string&)> loadWidgetFromMemory,
                                                         std::function<Project365::Widget(const std::string&)> loadWidgetFromWebRequest)
  {
  if (rstrWidgetRef.find(“Database”) != std::string::npos)
    {
    return loadWidgetFromDatabase(rstrWidgetRef);
    }
  else if (rstrWidgetRef.find(“Web Request”) != std::string::npos)
    {
    return loadWidgetFromWebRequest(rstrWidgetRef);
    }
  else
    {
    return loadWidgetFromMemory(rstrWidgetRef);
    }
  }

The nice thing about this is that the production calling code can remain unchanged because of the default argument. However, in the unit testing code, we now have the ability to provide an alternative implementation and inject this into the production code. This function that we inject could be a lambda, a more traditional functor or just plain old function). This is what renders the original function that I want to test unit testable.

An implementation in the Google test framework of a test could look something like this:

// Dummy / mock loaders so that we can test which have been called

auto databaseLoader = [&fDatabaseRoutingCalled, &aWidget] (const std::string&) -> Widget { fDatabaseRoutingCalled = true; return aWidget; };
auto webLoader = [&fWebRoutingCalled, &aWidget] (const std::string&) -> Widget { fWebRoutingCalled = true; return aWidget; };
auto memoryLoader = [&fMemoryRoutingCalled, &aWidget] (const std::string&) -> Widget { fMemoryRoutingCalled = true; return aWidget; };

// Hook into production code
ProductionCodeLoadWidget(“DatabaseRef12345” , databaseLoader, webLoader, memoryLoader);

// Expectations
EXPECT_EQ(fDatabaseRoutingCalled, true);
EXPECT_EQ(fWebRoutingCalled, false);
EXPECT_EQ(fMemoryRoutingCalled, false);

Hope you find this technique useful. The full code example can be found in my programming 365 github repo (“Day19”).

A good old fashioned intro

In this blog, I’ll be static casting some random topics: I’ll cast off all safety catches afforded by normal reality and twisting topics to fit into my twisted reality. That’s at least what I’d like to think. Most likely, I’ll just repeat conventional wisdom spouted by everyone else in yet another place.

Enough of the fluff.

The inspiration behind this blog is among other things this blog post by Jeff Atwood.
The other reason for starting the blog is that I need somewhere to store my stream of consciousness for all of this computing stuff. Bookmark collections, dropbox folders etc. just don’t seem to do it for me. So maybe something more stream-like will do.

Topics here are likely to include little series & posts on:

  • Containers
  • Algorithms
  • Some other code katas
  • Multi-Threading
  • UI & Graphics work with C++
  • C++ libraries
  • Financial libraries
  • Unit testing
  • Design patterns (both OO and enterprise)
  • T-SQL
  • SOA & web services
  • Mobile & web development (particularly hybrid / HTML & javascript based apps)
  • Agile practices
  • Visual Studio & TFS

Ironically (and in a half-hearted gesture of neutrality), any code which I’ll link to / mention in the blog will be hosted on a – currently very empty – Github repo and not in a TFS service.

I’ll also try to review (semi-interesting) books, videos and talks.

Altogether, I hope to post at least once a week. Looking at this list, it’ll take ages to get anywhere at that rate though. Never mind – maybe I’ll just ignore all of the above and ramble about photography, running and climbing. Some of which I sometimes indulge in in my spare time.