Skip to content

Developers Blog

ZahlGraf edited this page Oct 8, 2015 · 7 revisions

Developers Blog

08.10.2015 - Progress on Unit Tests

As I told some days ago, the version 0.3 will include unit test support. Now I will tell you some details about this. Basically I regret, that I have not added any unit test so far. But in version 0.3 I will include unit tests for the whole library, that checks every function in the public interface. I think this is essential for further refactoring or optimizing of the internal structures.

As this should increase the stability of the lib, it also helps users directly when writing their own tests. With version 0.3 the public interface will contain a full Unit Test Mock of the IMGUI handle class, that should help you as developer to reduce the complexity of your own tests. This Mock-class is prepared for CppUTest and CppUMock, a lightweight unit test framework.

Why CppUTest/CppUMock and not another fancy unit test framework?

I had a hard job to decide for a specific unit test framework. I did not have any special requirements in my mind, except of it should be easy to use. From my daily job I'm familiar with Unity and CMock and for my private projects I always used CppUTest with great success. However, I'm always open for new ideas, thus I decided to try out some new unit test frameworks in this project.

First of all I had a look at Boost.Test. I guess there are 10 types of C++ programmers out there: The first group loves Boost and the other group hates Boost. I am a developer who loves Boost, because it gave me for so many projects an easy way to implement complex stuff. For me Boost is some kind of unofficial standard library. And the only real disadvantage of it is the long compile time due to templates. However with a state of the art compiler like MSVC, GCC, CLang and Intel, you can easily precompile the headers to work around this. This means I really wanted to use Boost.Test first, because I'm familiar with this library and it has many different assertions, that helps me to understand fails as fast as possible. However, Boost.Test shows major issues with my Eclipse Indexer, thus it shows a lot of syntax errors even if the code compiled perfectly. It seems to be a common issue with Boost.Test, that IDE indexer don't understand it correctly.

So I decided to not use Boost.Test. The next candidate on my list was GoogleTest and GoogleMock. GoogleTest has a very verbose output, but I like it. It helps me to understand very fast what is going on. Furthermore you can easily add new functionality to it by using plugins. I added a memory leak detection plugin and was able to detect a small memory leak inside the IrrIMGUI library (that will be fixed with 0.3). So I would say, it was a great success? Unfortunately not: Even if GoogleTest is really cool, the GoogleMock framework was a major blocking point for me. It produces permanently memory leaks in my tests, since it allocates some heap data that persists across the test-boundaries. Of course these are not real memory leaks, but I did not find any way to distinguish between real memory leaks and framework related memory allocation. After one day of testing I gave up here: The GoogleMock memory allocation is a real impediment for me.

Then I had a look at CppTest. I think this was the first available Unit Test framework for C++. And I noticed, that there was almost no maintenance done for it the last months. Furthermore the library was not easy to compile, because it is missing a good portable make-system (like CMake).

I also looked at FakeIt and HippoMocks. Booth mocking frameworks are very modern and uses the latest C++11 features to create a mock out of an interface almost automatically. A really fancy idea and all the example code looks very promising. Booth are also single-header frameworks, so integrating them into your project is really easy. However booth seems to have major issues with x64 compile target. Unfortunately x64 is my personal primary development platform, so I simply cannot use it!

In the end, I decided to use the good old CppUTest and CppUMock. Booth are easy to use, even if creating Mocks with CppUMock is not perfect. However CppUTest has a very nice memory leak detection that works without issues for IrrIMGUI.

Dependency Injection Support

Version 0.3 will support you with some basic dependency injection features. The goal behind this is to help all IrrIMGUI users to write tests without having the full IrrIMGUI dependencies included. For example there is now an official interface to create with createIMGUI(...) a Mock object instead of a real IMGUI Handle. Then you can easily check, if your application uses this Mock object in a correct way. It helps you to decouple the IrrIMGUI library from your application in your tests.

Look at this example:

// First include all necessary headers
#include <IrrIMGUI/UnitTest/UnitTest.h>
#include <IrrIMGUI/UnitTest/IIMGUIHandleMock.h>
#include <IrrIMGUI/IncludeIrrlicht.h>

using namespace IrrIMGUI;

// Create a test group for CppUTest
TEST_GROUP(IIMGUIHandleMock)
{};

// Write your CppUTest Test-Case
TEST(IIMGUIHandleMock, createMock)
{
  // Create an Irrlicht NULL driver - this is a perfect way to to have a dummy driver in your application.
  irr::IrrlichtDevice * const pDevice = irr::createDevice(irr::video::EDT_NULL);

  // This tells the IrrIMGUI factory function to create a mock instead of a real object
  IrrIMGUI::UnitTest::IIMGUIHandleMock::enableMock();

  // Define the expected calls here:
  // 1.) First we want to check, if the constructor of the mock has been called.
  mock().expectOneCall("IrrIMGUI::UnitTest::IIMGUIHandleMock::IIMGUIHandleMock").withParameter("pDevice", pDevice).ignoreOtherParameters();

  // 2.) We just ignore other calls.
  mock().ignoreOtherCalls();

  // This code can be in your application: It normally creates the IMGUI Handle object,
  // but for this test it creates the Mock object (since we enabled it above) and thus
  // it will call the Mock constructor.
  IIMGUIHandle * const pGUI = createIMGUI(pDevice);

  // You can use the Mock object like a normal IIMGUIHandle object, your application
  // will not see any difference, except that there is no functionally behind and you can 
  // just check the calls to it with the mocking framework. 
  pGUI->drop();

  // This tells the IrrIMGUI factory function to create next time a normal object. 
  IrrIMGUI::UnitTest::IIMGUIHandleMock::disableMock();

  return;
}

Of course you can also create your own classes that fulfil the IIMGUIHandle interface. For example your own mock. In this case you can simply write your own factory function and inject this factory function into the IrrIMGUI library. This can be done by using the function IrrIMGUI::Inject::setIMGUIFactory(...).

// include header for injection feature
#include <IrrIMGUI/Inject/IrrIMGUIInject.h>

// Write your own factory function
IIMGUIHandle * createMyHandle(irr::IrrlichtDevice * pDevice, IrrIMGUI::CIMGUIEventStorage * pEventStorage = nullptr, IrrIMGUI::SIMGUISettings const * pSettings = nullptr)
{
  return new CMyIMGUIHandle(pDevice, pEventStorage, pSettings);
}

// Later in your code call:
IrrIMGUI::Inject::setIMGUIFactory(createMyHandle);

// This the IrrIMGUI library to use your factory function every time when your application calls createIMGUI(...)

Attenion: You can easily decouple the IrrIMGUI dependency from your application with the Mocking-feature. But you cannot do the same with the IMGUI functions that are called directly from your application. To decouple the IMGUI dependency you must use a framework like CMock, that substitutes the IMGUI functions with mock-functions on linker level.

However the IrrIMGUI library mock is prepared for a situation, where you still call the correct IMGUI functions. It will pass a minimal amount of data to IMGUI, to prevent the IMGUI library from raising errors. Thus you can use the IrrIMGUI Mock and still call IMGUI functions in your application, without getting errors from IMGUI.

06.10.2015 - A version for testability

Anything not testable is useless. (From Uncle Bob)

At the moment I prepare a bigger change that increases the testability of IrrIMGUI. This change will not introduce fancy new features, but it will increase the stability on long term view and make it easier for projects that uses this library to check the behaviour of it's own logic.

However this will lead to a small interface break. It is not a big issue, but version 0.3 will not run out of the box. You need to adapt your project on two points:

1.) Factory function for IMGUI handle

You cannot create an IrrIMGUI handle by new anymore. Instead of this you need to call a factory function, that assembles and creates this handle for you. This is the same way like Irrlicht does it:

Instead of

  // Create GUI object
  CIMGUIHandle * const pGUI = new CIMGUIHandle(pDevice, &EventReceiver);

You should write this in future:

  // Create GUI object
  IIMGUIHandle * const pGUI = createIMGUI(pDevice, &EventReceiver);

2.) Drop it, do not delete it!

You should not delete the IMGUI handle object anymore, but you can tell the object to delete itself:

Instead of

  delete(pGUI);

You should write this in future:

  pGUI->drop();

I guess for every experienced Irrlicht developer both will look quite familiar, right?

There are two reasons for the first change that affects the creation of the IMGUI handle object: Having an interface of the IMGUI handle will enable the users to enhance or adapt the functionalities of the handle by inherit from this interface. For example you can create your own handle, that is a wrapper around the original handle. Maybe for spying its actions. Or you can create a mock for your unit tests.

Actually the next version of IrrIMGUI will also deliver a full mock of the IMGUI handle for the CppUTest framework, so in your unit tests, you can create an object of this mock to check the calls to the handle.

There is also a good reason for the second interface change that affects the deletion of the IMGUI handle object. The next version will contain a counted reference class like Irrlicht uses it. Thus you can grab the IMGUI handle object if another object uses it and drop it later, when this object does not need it anymore. When you call drop more times than grab the object will destroy itself.

This is an efficient way to prevent a too early destruction of the IMGUI handle object when different other objects still uses the reference to it. By the way: The IMGUI handle object will now do the same with the Irrlicht device object. Thus in version 0.3 you don't need to take care about the order of object deletion anymore.