Creating a Test Double for rlog

We don’t have to stub everything that rlog defines, only the things our test executable requires. We start by commenting out the line in the makefile that links rlog into the test executable. Here’s our update to CMakeLists.txt (we’re using CMake):

wav/7/CMakeLists.txt
 
project(SnippetPublisher)
 
cmake_minimum_required(VERSION 2.6)
 
 
include_directories($ENV{BOOST_ROOT}/ $ENV{RLOG_HOME} $ENV{CPPUTEST_HOME}/include)
 
link_directories($ENV{RLOG_HOME}/rlog/.libs $ENV{CPPUTEST_HOME}/lib)
 
set(Boost_USE_STATIC_LIBS ON)
 
 
add_definitions(-std=c++0x)
 
 
set(CMAKE_CXX_FLAGS "${CMAXE_CXX_FLAGS} -DRLOG_COMPONENT=debug -Wall")
 
set(sources WavReader.cpp WavDescriptor.cpp)
 
set(testSources WavReaderTest.cpp)
 
add_executable(utest testmain.cpp ${testSources} ${sources})
 
add_executable(SnippetPublisher main.cpp ${sources})
 
 
find_package(Boost $ENV{BOOST_VERSION} COMPONENTS filesystem system)
 
target_link_libraries(utest ${Boost_LIBRARIES})
 
target_link_libraries(utest CppUTest)
 
target_link_libraries(utest pthread)
 
target_link_libraries(utest rt)
*
#target_link_libraries(utest rlog)
 
 
target_link_libraries(SnippetPublisher ${Boost_LIBRARIES})
 
target_link_libraries(SnippetPublisher pthread)
 
target_link_libraries(SnippetPublisher rlog)

Now when we build, we receive numerous link errors.

 
Linking CXX executable utest
 
CMakeFiles/utest.dir/WavReader.cpp.o: In function `WavReader::WavReader(
 
std::string const&, std::string const&)':
 
WavReader.cpp:(.text+0xef): undefined reference to
 
`rlog::StdioNode::StdioNode(int, int)'
 
WavReader.cpp:(.text+0x158): undefined reference to
 
`rlog::GetComponentChannel(char const*, char const*, rlog::LogLevel)'
 
WavReader.cpp:(.text+0x17c): undefined reference to
 
`rlog::GetComponentChannel(char const*, char const*, rlog::LogLevel)'
 
WavReader.cpp:(.text+0x18e): undefined reference to
 
`rlog::StdioNode::subscribeTo(rlog::RLogNode*)'
 
WavReader.cpp:(.text+0x1e4): undefined reference to
 
`rlog::PublishLoc::~PublishLoc()'
 
...

We need to supply stubs for each of those attempts to hook into rlog. Here is one approach:

  1. Copy over an rlog header file into a subdirectory, renaming it as a .cpp file.

  2. Edit the .cpp file, converting prototypes into stubs that do nothing other than return a default value if required.

  3. Compile and repeat the prior steps until no link errors exist.

Since StdioNode appears at the top of our link error list, we start there.

wav/8/rlog/StdioNode.cpp
 
#include <rlog/StdioNode.h>
 
 
class​ RLogNode;
 
class​ RLogData;
 
 
using​ ​namespace​ std;
 
 
namespace​ rlog {
 
StdioNode::StdioNode(​int​ _fdOut, ​int​ flags)
 
: RLogNode() {}
 
StdioNode::StdioNode(​int​ _fdOut, ​bool​ colorizeIfTTY)
 
: RLogNode(), fdOut( _fdOut ) { }
 
StdioNode::~StdioNode() { }
 
void​ StdioNode::subscribeTo( RLogNode *node ) { }
 
void​ StdioNode::publish( ​const​ RLogData &data ) { }
 
}

That’s not too tough, but converting headers into implementation files can get a bit tedious and tricky at times. (Maybe there’s a magic tool out there that can do this for you!) Here are a few things (and not everything) to consider:

  • As the very first thing you do, #include the header from whence you created the implementation file.

  • You may need to wrap the implementations in a namespace.

  • Remove virtual and static keywords.

  • Remove public: and other access specifiers.

  • Remove member variables and enums.

  • Be careful about removing preprocessor defines and typedefs.

  • Return the simplest possible type if the function specifies a return value—for example, 0, false, "", a null pointer, or an instance created using a no-arg constructor.

  • If you must return a const reference, create a global and return that.

  • Don’t forget to scope the function to the appropriate class.

  • Don’t sweat the way it looks when done; the important thing is that it compiles.

We add a makefile that builds our new stub library.

wav/8/rlog/CMakeLists.txt
 
project(rlogStub)
 
cmake_minimum_required(VERSION 2.6)
 
 
include_directories($ENV{RLOG_HOME})
 
 
add_definitions(-std=c++0x)
 
 
set(CMAKE_CXX_FLAGS "${CMAXE_CXX_FLAGS} -DRLOG_COMPONENT=debug -Wall")
 
set(sources StdioNode.cpp)
 
 
add_library(rlogStub ${sources})
 
 
target_link_libraries(rlogStub pthread)

We update our test build to incorporate the stub library. The production app, SnippetPublisher, continues to use the production rlog library.

wav/8/CMakeLists.txt
 
project(SnippetPublisher)
 
cmake_minimum_required(VERSION 2.6)
 
 
include_directories($ENV{BOOST_ROOT}/ $ENV{RLOG_HOME} $ENV{CPPUTEST_HOME}/include)
 
link_directories($ENV{RLOG_HOME}/rlog/.libs $ENV{CPPUTEST_HOME}/lib)
 
set(Boost_USE_STATIC_LIBS ON)
 
*
add_subdirectory(rlog)
 
add_definitions(-std=c++0x)
 
 
set(CMAKE_CXX_FLAGS "${CMAXE_CXX_FLAGS} -DRLOG_COMPONENT=debug -Wall")
 
set(sources WavReader.cpp WavDescriptor.cpp)
 
set(testSources WavReaderTest.cpp)
 
add_executable(utest testmain.cpp ${testSources} ${sources})
 
add_executable(SnippetPublisher main.cpp ${sources})
 
 
find_package(Boost $ENV{BOOST_VERSION} COMPONENTS filesystem system)
 
target_link_libraries(utest ${Boost_LIBRARIES})
 
target_link_libraries(utest CppUTest)
 
target_link_libraries(utest pthread)
*
target_link_libraries(utest rlogStub)
 
 
target_link_libraries(SnippetPublisher ${Boost_LIBRARIES})
 
target_link_libraries(SnippetPublisher pthread)
 
target_link_libraries(SnippetPublisher rlog)

An attempt to build with the StdioNode.h stub fails. We add stubs for RLogChannel.h, RLogNode.h, and rlog.h, each an implementation of the actual rlog header file. Here’s the implementation for RLogChannel.h, slightly more interesting because of the need to supply return values:

wav/9/rlog/RLogChannel.cpp
 
#include "rlog/RLogChannel.h"
 
#include <string>
 
#include <iostream>
 
 
namespace​ rlog
 
{
 
RLogChannel::RLogChannel( ​const​ std::​string​ &name, LogLevel level ){ }
 
RLogChannel::~RLogChannel(){}
 
void​ RLogChannel::publish(​const​ RLogData &data){}
 
 
std::​string​ nameReturn(​""​);
 
const​ std::​string​ &RLogChannel::name() ​const​ { ​return​ nameReturn; }
 
 
LogLevel RLogChannel::logLevel() ​const​ { ​return​ LogLevel(); }
 
void​ RLogChannel::setLogLevel(LogLevel level) {}
 
RLogChannel *getComponent(RLogChannel *componentParent,
 
const​ ​char​ *component){ ​return​ 0; }
 
}

We work on creating one stub at a time, remembering to update our makefile for each.

wav/9/rlog/CMakeLists.txt
 
set(sources rlog.cpp RLogChannel.cpp RLogNode.cpp StdioNode.cpp)

We attempt a build with each new stub we put in place. After getting all four stubs in place, we experience the exhilaration of link and test success! Yay. Elapsed time: perhaps twenty minutes. Staving off continual future headaches seems well worth the effort.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.187.233