Unit Testing with GTest and GMock

In recent years, I’ve found myself writing less user interface code and more server code (typically COM servers that are exercised on client workstations or on nodes in a compute farm). Given the lack of a UI for driving and testing the code (excepting spreadsheets), automated tests are vital to achieve a high degree of code coverage.
The Art Of Unit Testing
Given that I’ve been doing this for years now, I was surprised to learn that I haven’t been writing unit tests, as I previously supposed. According to The Art of Unit Testing, the tests I’ve been writing are typically interaction tests. These are useful too, but unless a component can be tested in isolation with tests that run without delay due to network/database interaction, it isn’t a unit test.

Since reading the book, I’ve adopted the Google Test framework for both writing unit tests and implementing mock objects to accompany the tests. Without a good library for writing mock objects, you’re dragged straight back in to writing tests that call other objects in your library. With GMock, you can easily create mock objects and inject behaviour into them in order to test your server code in various scenarios. Using GTest and GMock is easy – just call RUN_ALL_TESTS() in main, and the framework discovers all the unit test you’ve written and launches them:

#include "gmock\gmock.h"
using namespace testing;

// Start writing unit tests here!

int _tmain(int argc, _TCHAR* argv[])
{
    ::InitGoogleMock( &argc, argv );
    return RUN_ALL_TESTS();
}

Here’s a simple example that defines a WeatherStation interface and a UserInterface class. We wish to test the UserInterface, but the weather station isn’t written yet – so we define a MockWeatherStation, and set up tests to invoke the UserInterface in different situations:

#include "gmock\gmock.h"

#include <iostream>
#include <list>
#include <memory>

class WeatherStation
{
public:
    virtual ~WeatherStation(){};

    typedef enum
    {
        North, South, East, West
    } Direction;

    typedef enum
    {
        Optimistic, Pessimistic
    } Outlook;

    // NB Semantics on wind deliberately ugly to show a neat feature in gmock
    virtual void wind( Direction* pDirection, double* strength ) const = 0;
    virtual double rainfall() const = 0;
    virtual std::string prediction( Outlook outlook ) const = 0;
};

class UserInterface
{
public:
    UserInterface( const std::shared_ptr<WeatherStation>& weather_station ) :
        weather_station_( weather_station )
    {
    }

    typedef enum
    {
        Heavy, Medium, Light
    } Range;

    Range rain()
    {
        auto rainfall = weather_station_->rainfall();
        if ( 0.0 <= rainfall && rainfall < 2.0 ) return Light;
        else if ( 2.0 <= rainfall && rainfall < 4.0 ) return Medium;
        else return Heavy;
    }

    Range wind()
    {
        WeatherStation::Direction direction;
        double strength;
        weather_station_->wind( &direction, &strength );

        if ( 0.0 <= strength && strength < 5.0 ) return Light;
        else if ( 5.0 <= strength && strength < 10.0 ) return Medium;
        else return Heavy;
    }

    std::pair<std::string, std::string> predict_range()
    {
        return std::make_pair( 
            weather_station_->prediction( WeatherStation::Optimistic ),
            weather_station_->prediction( WeatherStation::Pessimistic ) );
    }

private:
    std::shared_ptr<WeatherStation> weather_station_;
};

using namespace testing;

class MockWeatherStation : public WeatherStation
{
public:
    MOCK_CONST_METHOD0( rainfall, double() );
    MOCK_CONST_METHOD2( wind, void(WeatherStation::Direction*, double*) );
    MOCK_CONST_METHOD1( prediction, std::string( WeatherStation::Outlook ) );
};

TEST( WeatherStationUserInterface, rain_should_be_heavy )
{
    auto weather_station = std::make_shared<MockWeatherStation>();
    // GMock: specify a simple return value using Return(x)
    // Here, part of the test is that the Mock should be called once,
    // hence the 'WillOnce' call (more than one call would be an error).
    // If multiple calls should happen during the test, 
    // use 'WillRepeatedly' instead.
    EXPECT_CALL( *weather_station, rainfall() )
        .WillOnce( Return(5.0) );
    UserInterface ui( weather_station );
    EXPECT_EQ( UserInterface::Heavy, ui.rain() );
}

TEST( WeatherStationUserInterface, wind_should_be_light )
{
    auto weather_station = std::make_shared<MockWeatherStation>();
    // GMock: specify out parameter values using SetArgPointee
    EXPECT_CALL( *weather_station, wind(_,_) )
        .WillOnce( DoAll( SetArgPointee<0>( WeatherStation::North ),
                          SetArgPointee<1>( 0.5 )) );
    UserInterface ui( weather_station );
    EXPECT_EQ( UserInterface::Light, ui.wind() );
}

TEST( WeatherStationUserInterface, predictions_are_displayed )
{
    auto weather_station = std::make_shared<MockWeatherStation>();
    // GMock: inject more complex logic using C++11 lambdas,
    // and pattern match on the input value
    EXPECT_CALL( *weather_station, prediction(WeatherStation::Optimistic) )
        .WillOnce( Invoke( []( WeatherStation::Outlook _ ) -> std::string
            {
                return "Sunny";
            }) );
    EXPECT_CALL( *weather_station, prediction(WeatherStation::Pessimistic) )
        .WillOnce( Invoke( []( WeatherStation::Outlook _ ) -> std::string
            {
                return "Overcast";
            }) );

    UserInterface ui( weather_station );
    auto predicted_range = ui.predict_range();
    EXPECT_EQ( "Sunny", predicted_range.first );
    EXPECT_EQ( "Overcast", predicted_range.second );
}

When you run the executable, it’s easy to spot if the tests pass or fail:
WeatherStationOutput

As a bonus, Visual Studio 2012 has neat integration for GoogleTest:
WeatherStation

See also

7 Comments

Filed under C++, C++ Code, Programming

C++: Race conditions and Data races

According to this discussion on Stack Overflow, we should make a distinction between race conditions and data races. This blog post defines the terms and gives a neat example where the code is modified to exhibit zero, one or both behaviours.

Here’s an example of a race condition – the ordering of the execution affects the outcome (this can occur if one thread checks a value then performs an action, giving another thread the change to mutate the variable in between):

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

And here’s an example of a data race – a variable is mutated by multiple threads without synchronisation:

// Execute this function on five threads simultaneously
for ( int i = 0; i < 10000; i++ )
{
   x = x + 1; 
}

In both cases, use of a synchronisation object across all the threads involved (e.g. a mutex) would address the issue.

Leave a comment

Filed under C++, C++ Code, Programming

C++: Function overload preferences

The function overload rules in C++ are sometimes surprising. Herb Sutter wrote an excellent Guru of the Week article on function overload rules some time ago, but here’s some code to differentiate between some of the common overloads:

#include <iostream>
#include <string>

template<typename T>
void foo(T t)
{
    std::cout << "Generic Template function: " << t << "\n";
}

template<>
void foo<int>(int i)
{
    std::cout << "Function template specialization for int: " << i << "\n";
}

template<>
void foo<bool>(bool b)
{
    std::cout << "Function template specialization for bool: " << b << "\n";
}

void foo( double d )
{
    std::cout << "Non-template overload for double: " << d << "\n";
}

void foo( int i )
{
    std::cout << "Non-template overload for int: " << i << "\n";
}

int main()
{
    std::string s = "Hello, World";
    foo(s); // Calls generic template

    bool b = true;
    foo(b); // Calls template specialization

    double d = 1.0;
    foo(d); // Exact match to non-template overload

    int i = 0;
    foo(i); // Exact match (better than template specialization)

    short sh = 255;
    foo(sh); // Not exact match, calls generic template

    return 0;
}

FunctionOverloadOutput

Leave a comment

Filed under C++, C++ Code, Programming

Book Review: A Wanted Man, Lee Child

A Wanted ManI’d read a few negative reviews of this Jack Reacher thriller before I read the book. I agree that it’s different to the majority of the books in the series: for one thing, the author concentrates on the cerebral side of Reacher’s character and concentrates too much on his exceptional memory for phone numbers and mathematical abilities (these aren’t pertinent to the plot so why keep referring to them?); for another, there’s far less action in this book (usually, Reacher’s run into trouble at a bar within the first few pages, here we’re into the finale before he gets into a fight). It’s not really up to the usual standards, but it’s still a better read than a couple of other books I failed to get into recently.
20130418-193203.jpg

2 Comments

Filed under Book Review

C++: functional programming and type classes

Functional C++ posted an article introducing type classes for C++.

Leave a comment

Filed under C++, Programming

C++: noexcept specification generated for destructors in C++11

Andrzej Krzemienski’s blog has this post on the subject of noexcept:

Even if you explicitly declare your destructor without any exception specification, the compiler will add one for you: the same as it would add if it had to implicitly generate the destructor. If you do not like the exception specification generated by the compiler, you have to explicitly specify it.

So if there’s a reason to throw from a destructor (which is typically frowned upon), you’d better declare noexcept(false).

Leave a comment

Filed under C++, Programming

C++: Resumable functions, Async and Await

Interesting post from Jens Weller on the new concurrency features in C++ 11 and C++ 14. He gives examples of code written using standard library async, futures and “.then()” with lamdbas, compared to the simplicity of expressing the same functionality with the proposed resumable functions (that is, resumable and await as language keywords).

Whilst resumable and await won’t be part of the language until at least C++17, Weller points out that Microsoft may put implementations into Visual Studio well before that. Here’s the paper, N3722.

Leave a comment

Filed under C++, Programming

Goldman Sachs automated trading error

Bloomberg reports that Goldman Sachs is the latest firm to suffer from a programming error in their automated trading software:

An internal system that Goldman Sachs uses to help prepare to meet market demand for equity options inadvertently produced orders with inaccurate price limits and sent them to exchanges

Participants in trades caused by error can appeal, and exchanges are reviewing and busting trades. It seems a large number of trades occurred because quotes entered the market at a price of $1:

Of the 500 biggest options trades in the first 15 minutes markets were open today, 405 of them were for tickers starting with H through L and priced at $1, according to data compiled by Trade Alert LLC and Bloomberg

.

Leave a comment

Filed under Finance

How to implement a “virtual” operator<

In order to support a collection of heterogenous objects, I implemented a std::set<std::shared_ptr<Base>> then inherited the derived classes from Base.  That works fine, except that the ordering and uniqueness is controlled by the object addresses, not the values of the derived objects.  Ideally, one would make operator< virtual on Base, but that won’t work here because the signature of operator< for each of the derived classes is different:

bool Base::operator<( const Base& rhs ) const
{  /* implementation */ }

bool A::operator<(const A& rhs ) const
{ /* implementation */  }

bool B::operator<(const B& rhs ) const
{ /* implementation */  }

Instead, this solution follows the “Non-Virtual Interface” idiom and leaves operator< non-virtual. Instead, operator< delegates to a separate virtual method, compares_less. In order to provide a strict-weak-ordering, the objects of distinct types need to be handled too – it’s not enough to fall back to comparing pointer addresses (the addresses could provide an inconsistent ordering).  Here, inter-type comparisons are handled by ordering on the type name (supplied by another virtual method).

// LessThan.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <set>
#include <string>

template<typename Container>
void dump( const Container& elements )
{
  for ( auto it = elements.begin(); it != elements.end(); ++it )
  {
    if ( it != elements.begin() )
    {
      std::cout << ", ";
    }
    std::cout << (*it);
  }
  std::cout << std::endl;
}

class Base
{
public:
  bool operator<( const Base& rhs ) const
  {
    return this->compares_less( rhs );
  }

  virtual std::ostream& dump( std::ostream& os ) const = 0;

  virtual bool compares_less( const Base& rhs ) const = 0;
  virtual std::string type_name() const = 0;
};

class A : public Base
{
  int a_;
public:
  A(int a) : a_(a)
  {}

  int a() const { return a_; }

  virtual std::ostream& dump( std::ostream& os ) const
  {
    os << a_;
    return os;
  }

  virtual bool compares_less( const Base& rhs ) const
  {
    if ( auto pA = dynamic_cast<const A*>( &rhs ) )
    {
      return a_ < pA->a_;
    }
    return this->type_name() < rhs.type_name();
  }

  virtual std::string type_name() const
  {
    return "A";
  }
};

class B : public Base
{
  std::string b_;
public:
  B( std::string b ) : b_(b)
  {}

  std::string b() const { return b_; }

  virtual bool compares_less( const Base& rhs ) const
  {
    if ( auto pB = dynamic_cast<const B*>( &rhs ) )
    {
      return b_ < pB->b_;
    }
    return this->type_name() < rhs.type_name();
  }

  virtual std::string type_name() const
  {
    return "B";
  }

  virtual std::ostream& dump( std::ostream& os ) const
  {
    os << b_;
    return os;
  }
};

std::ostream& operator<<( std::ostream& os, const std::shared_ptr<Base>& b )
{
  b->dump( os );
  return os;
}

struct LessThan
{
  bool operator()( const std::shared_ptr<Base>& lhs, const std::shared_ptr<Base>& rhs ) const
  {
    return *lhs < *rhs;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{
  std::set<std::shared_ptr<Base>, LessThan> elements;

  elements.insert( std::make_shared<A>( 1 ) );
  elements.insert( std::make_shared<A>( 10 ) );
  elements.insert( std::make_shared<B>( "World" ) );
  elements.insert( std::make_shared<A>( 7 ) );
  elements.insert( std::make_shared<B>( "C++ says" ) );
  elements.insert( std::make_shared<A>( 3 ) );
  elements.insert( std::make_shared<B>( "Hello" ) );
  elements.insert( std::make_shared<A>( 5 ) );

  dump( elements );

  return 0;
}

Here’s the output, showing that the A’s and B’s are ordered as expected:
VirtualLessThanOutput

Leave a comment

Filed under C++, C++ Code, Programming

Herb Sutter GotW94: AAA Style (Almost Always Auto)

Herb Sutter’s Guru of the Week article on Almost Always Auto is a tour de force covering everything you always wanted to know about auto.

Leave a comment

Filed under C++, Programming