How to fake C++ objects with Isolator++ (Beta)

It seems like everything in the C++ world is harder – you have two files per class, no garbage collection and you need to know your pointer tricks to get things done. It would have been only natural that unit tests would flourish in such a world that a project could live or die by it’s memory leaks. Unfortunately this is not the case, perhaps one of the reasons that the practice of unit testing code is not that common is that like everything else – writing unit test in C++ is not that easy, at least not easy as it is on the managed world.

The good news is that it got easier with the new beta of Isolator++ that brings the proven methodologies and expertise from the .Net Isolator to C++ land.

In this post I’ll show how to fake classes in order to write simple, maintainable unit tests.

The problem at hand

Our story begins with a need to create a BusinessObject that can be persisted (i.e. saved to database). We want to make sure that after a newly created object is saved ,its dirty flag is set to false.

Here is my simple BusinessObject implementation:

Header (.h)

#pragma once

 

class DAL;

 

class BusinessObject

{

    int m_id;

    bool m_isDirty;

    DAL* m_dataAccess;

 

public:

    BusinessObject(int id, DAL* dataAccess);

    ~BusinessObject(void);

 

    bool IsDirty()const{return m_isDirty;}

    void Save();

};

 

Implementation (.cpp)

#include "StdAfx.h"

#include "BusinessObject.h"

#include "DAL.h"

 

BusinessObject::BusinessObject(int id, DAL* dataAccess): m_id(id), m_dataAccess(dataAccess), m_isDirty(true)

{

}

 

BusinessObject::~BusinessObject(void)

{

}

 

void BusinessObject::Save()

{

    m_dataAccess->Save(*this);

 

    m_isDirty = false;

}

 

As you can see creating a new object sets the IsDirty flag to true and calling Save sets it to false – per our requirements.

Testing the BusinessObject

I’ve used google’s testing framework to write the unit test and it’s as simple as you’d expect it to be:

#include "stdafx.h"

#include <gtestgtest.h>

 

#include "BusinessObject.h"

#include "DAL.h"

 

class BusinessObjectTests : public ::testing::Test

{

};

 

TEST_F(BusinessObjectTests, IsDirtySetToFalseOnSave)

{

    DAL* dataAccess = new DAL();

    BusinessObject* bo = new BusinessObject(1, dataAccess);

 

    bo->Save();

 

    ASSERT_FALSE(bo->IsDirty());

}

 

I find it quite readable – even if you are not familiar with GTest – it’s a single test that does the following:

  1. Create a new data access layer
  2. Create a new BusinessObject
  3. Call Save
  4. Assert that IsDirty is set to false

For more information on writing tests using GTest – have a look at the documentation or Isolator++ getting started page.

Unfortunately running the test fails – miserably:

image 

As you might have already guessed – the reason for this “crash” comes from the bowels of the DAL object. Because we do not have an actual database – in fact I haven’t even implemented it yet.

But I won’t let such trivialities as a missing database stop me – I want to test the logic of the object, not the way it’s saved. This is where Isolator++ comes in.

Isolating the business logic

What I need for the test to pass is to create a “fake” data access object. It may look like a regular object, but every method that gets called on it, doesn’t do anything.

Creating a fake object with Isolator++ is simple: just link to the IsolatorCore library and add and include Isolator.h and you’re set to go.

This is how the updated test looks like:

#include "stdafx.h"

#include <gtestgtest.h>

#include <isolator.h>

 

#include "BusinessObject.h"

#include "DAL.h"

 

class BusinessObjectTests : public ::testing::Test

{

};

 

TEST_F(BusinessObjectTests, IsDirtySetToFalseOnSave)

{

    DAL* dataAccess = FAKE(DAL);

 

    BusinessObject* bo = new BusinessObject(1, dataAccess);

 

    bo->Save();

 

    ASSERT_FALSE(bo->IsDirty());

}

 

Notice the FAKE macro that is used to create the DAL object.

And now the test should pass – which we can verify by running it:

image

That’s it. The very basics of Isolator++.

More information on faking objects can be found on Isolator++ online user guide

Happy coding

Dror B. Helper