Grouping template test fixtures - c++

I have a template test class which I am looking to write test fixtures for. I have the following snippet which works but it doesn't "group" the test fixtures together because of the template type so I have to run each of them separately rather than just once (i.e UTestClass). When I run UTestClass, it says No tests were found
Note that the snippet below allows accessing of member variable _value across different test fixtures too so I'd want to have this behavior.
Is there a way to group the template test fixtures together? Perhaps in a test suite or another class which allows each test to run ONLY with a specified type?
template<typename T>
struct UTestClass : public testing::Test
{
T _value;
};
using Float = UTestClass<float>;
using Double = UTestClass<double>;
TEST_F(Float, TestA)
{
// able to access _value
}
TEST_F(Double, TestB)
{
// able to access _value
}

TYPED_TEST_SUITE and TYPED_TEST are for such purposes.
template<typename T>
struct UTestClass : public testing::Test {};
using UTestClassTypes = ::testing::Types<float, double>;
TYPED_TEST_SUITE(UTestClass, UTestClassTypes);
TYPED_TEST(UTestClass, TestA) {
}

Related

Writing Unit-Test for a Class

I have a class with constructor having 6 arguments. I want to write a Test fixture for this class. I tried calling these arguments in the test constructor, but failed to create test fixture
class TestHandler
{
public:
using Buffer = common::dt::ByteBuffer;
using HardwareInterface =
common::interfaces::SyncBufferProducerConsumer<Buffer>;
explicit TestHandler(slave::cache::FullKeyValueCache&
cache, const CommandHandler& commandHandler,
const RTDCache& rtdCache, HardwareInterface&
hardwareInterface, bool& statusChanged, bool& alarmsChanged)
: m_keyValueCache(cache)
, m_commandHandler(commandHandler)
, m_rtdCache(rtdCache)
, m_hardwareInterface(hardwareInterface)
, m_statusChanged(statusChanged)
, m_alarmsChanged(alarmsChanged)
{
}
template <typename T>
void respond()
{
m_checksumHelper.checksumEnabled() =
m_commandHandler.checksumEnabled();
auto responseMessage =
SalviaSerial::traitsTemplate::Response();
fillResponse<T>(responseMessage);
common::dt::GuardedWriteBuffer<uint8_t>
writeBuffer(m_hardwareInterface);
common::extensionCards::library::serialise
(responseMessage, writeBuffer.get_range());
m_checksumHelper.calculateAndSetChecksum
(writeBuffer.get_range());
}
private:
template <typename T>
void fillResponse(SalviaSerial::traitsTemplate::Response&
response);
slave::cache::FullKeyValueCache& m_keyValueCache;
const CommandHandler& m_commandHandler;
const RTDCache& m_rtdCache;
HardwareInterface& m_hardwareInterface;
DOBusImplementation::ChecksumHelper m_checksumHelper;
bool& m_statusChanged;
bool& m_alarmsChanged;
};
I need to write a Test fixture for TestHandler class, later use this t4xt fixture to test different responses available. I need suggestions on calling this class in TestHandlerTest.cpp and a method to start unit test.
If you want to create a test fixture in Google Test, you’ll need to (a) inherit from the testing::Test class and (b) ensure your fixture class is default-constructible (can be constructed without any arguments).

Better MOCKing?

Question:
Let's say I have a class System which has some Component inside. In order to properly test the System I need to keep a pointer to Component in the System class, and design the Component to have an interface, IComponent, with virtual methods. Then in the test, I can create a mock of IComponent and give it to the System.
But in some situtations I don't want such approach.
There is other technique of using templates and specifying the Component as template parameter, like this:
template <class Component>
class System
{
// ...
Component _component;
};
Then, in my test I can create the System giving it a Mock of Component, like this:
System<MockComponent> theSystem;
The MockComponent does not necesarrily be inherited from IComponent, in my approach I dont want IComponent, I just want MockComponent to have some needed methods, the same as in Component.
But the problem with this approach is that I want to instruct the MockComponent what to do, give it some expectations and tell what to return. From the test I do not have access to the MockComponent because it lives in the System. If the System had a getter of Component then it would be OK, but sometimes I don't want to have a getter of Component in the System. Then, in the test, I need to create another class, MockSystem, and equip it with the getter of the component (and also make sure that the _component in the original System is in "protected" section).
template <Class Component>
MockSystem : public System
{
public:
Component GetComponent() { return _component; }
};
Then, in the test I can:
MockSystem<MockComponent> theSystem;
MockComponent mockComponent = theSystem.GetComponent();
EXPECT_CALL(mockComponnent, ...);
This approach works fine.
But... I wonder if there is a way to simplify this a bit.
What if I had a mechanism of generating, in compile time, the class of MockSystem, from the class of System? I mean I would like to obtain the class of System with getters for all template parameters.
I know that template metaprogramming can do miracles, but I am not an expert in TPM. I've read some examples and seen Boost::Hana in action, and wonder now if this is doable.
Has anyone of guys here heard of or seen a framework for something like this?
Or is there another approach?
You can define wrapper over your mock class - to allow access to mock:
struct ComponentMock
{
MOCK_METHOD0(foo, int());
};
struct ComponentMockWrapper
{
static ComponentMock* mock;
int foo()
{
return mock->foo();
}
};
ComponentMock* ComponentMockWrapper::mock;
Then, in your TestSuite:
class SystemTestSuite : public testing::Test
{
protected:
ComponentMock componentMock;
void SetUp() override
{
ComponentMockWrapper::mock = &componentMock;
}
System<ComponentMockWrapper> objectUnderTest;
};
And test like this:
TEST_F(SystemTestSuite1, shallFooComponent)
{
EXPECT_CALL(componentMock, foo());
objectUnderTest.foo();
}
But be aware of such problems like - what to do if 2 or more Component needed, or how to keep track of lifetime of testable Component...
Maybe better approach is to sacrifice a little encapsulation in favor of testability - i.e. get protected access to component:
template <class Component>
class System
{
protected:
Component& getComponent(); // for UT only
};
And allow public access in UT by promoting this function:
template <class Component>
class SystemTestable : public System<Component>
{
public:
using System<Component>::getComponent;
};
class SystemTestSuite : public testing::Test
{
protected:
SystemTestable<ComponentMock> objectUnderTest;
};

Specify constructor arguments for a Google test Fixture

With Google test I want to specify a Test fixture for use in different test cases.
The fixture shall allocate and deallocate objects of the class TheClass and its data management class TheClassData, where the data management class requires the name of a datafile.
For the different tests, the file name should vary.
I defined the following Fixture:
class TheClassTest : public ::testing::Test {
protected:
TheClassTest(std::string filename) : datafile(filename) {}
virtual ~TheClassTest() {}
virtual void SetUp() {
data = new TheClassData(datafile);
tc = new TheClass(data);
}
virtual void TearDown() {
delete tc;
delete data;
}
std::string datafile;
TheClassData* data;
TheClass* tc;
};
Now, different tests should use the fixture with different file names.
Imagine this as setting up a test environment.
The question: How can I specify the filename from a test, i.e. how to call a non-default constructor of a fixture?
I found things like ::testing::TestWithParam<T> and TEST_P, which doesn't help, as I don't want to run one test with different values, but different tests with one fixture.
As suggested by another user, you cannot achieve what you want
by instantiating a fixture using a non-default constructor. However,
there are other ways. Simply overload the SetUp function and
call that version explicitly in the tests:
class TheClassTest : public ::testing::Test {
protected:
TheClassTest() {}
virtual ~TheClassTest() {}
void SetUp(const std::string &filename) {
data = new TheClassData(filename);
tc = new TheClass(data);
}
virtual void TearDown() {
delete tc;
delete data;
}
TheClassData* data;
TheClass* tc;
};
Now in the test simply use this overload to set up filename:
TEST_F(TheClassTest, MyTestCaseName)
{
SetUp("my_filename_for_this_test_case");
...
}
The parameterless TearDown will automatically clean up when
the test is complete.
Use the current class as a base class for your fixtures:
class TheClassTestBase : public ::testing::Test {
protected:
TheClassTestBase(std::string filename) : datafile(filename) {}
...
};
For every specific filename - use derived fixture:
class TheClassTestForFooTxt : public TheClassTestBase {
protected:
TheClassTestForFooTxt() : TheClassTestBase ("foo.txt") {}
};
However this is extra step needed for every set of parameters - so you can try to use templates or macros to get it done with less effort. Like:
template <typename ClassTestTag>
struct ClassTestParams
{
static std::string filename;
};
template<typename ClassTestTag>
class TheClassTest : public TheClassTestBase {
protected:
TheClassTest() : TheClassTestBase (ClassTestParams<ClassTestTag>::filename) {}
};
Then - for every set of parameters - do that:
class FooTxtTag {};
template <> std::string ClassTestParams<FooTxtTag>::value = "foo.txt";
using TheClassTestForFooTxt = TheClassTest<FooTxtTag>;
TEST_F(TheClassTestForFooTxt, xxxx) {}
However - in your specific case - I would also try GoogleTest:type-parameterized-tests.
Another great way to deal with this is to just extend your fixture and in the extended class supply a new default constructor which calls through to the old one with the arguments you require. For example:
struct MySpecializedTestFixture : public GenericTestFixture
{
MySpecializedTestFixture() : GenericTestFixture("a thing", "another thing") {}
};
TEST_F(MySpecializedTestFixture, FancyTest)
{
// Use the thing environment and make some assertions.
}
If you overload the SetUp method as suggested here, and you want to ensure that you remember to use the overloaded SetUp, you can use an assertion in the TearDown method.
class my_fixture : public ::testing::Test
{
protected:
bool SETUP_HIT_FLAG = false;
void SetUp(double parameter)
{
...
SETUP_HIT_FLAG = true;
}
void TearDown() override
{
assert(SETUP_HIT_FLAG && "You forgot to call SetUp with your parameter!");
}
};
Another way using templates:
template<int N>
class Fixture : public ::testing::Test { ... }
using FixtureForTest = Fixture<1000>;
TEST_F(FixtureForTest, test) { ... }
For this specific case, I feel it is much easier to get rid of the test fixture altogether. The SetUp function can instead be replaced with a helper function that instantiates the class with the required file name. This permits the use of TEST instead of TEST_P or TEST_F. Now each test case is a standalone test which creates its own test class instances with the helper function or directly in the body of the test case.
For example:
using namespace testing;
TEST(FooClassTest, testCase1)
{
FooClass fooInstance("File_name_for_testCase1.txt");
/* The test case body*/
delete fooInstance;
}

How to make expectations on a mock object created inside the tested object?

I want to unit test a class that looks like this:
template <typename T>
class MyClass {
...
void someMethod() {
T object;
object.doSomething();
}
...
};
I want to unit test this class, so I create a mock class for T:
struct MockT {
...
MOCK_METHOD(doSomething, 0, void());
...
};
Then I want to use it in a test case:
BOOST_AUTO_TEST_CASE(testSomeMethod) {
MyClass<MockT> myClassUnderTest;
MOCK_EXPECT(???)....;
myClassUnderTest.someMethod();
}
How do I make an expectation for this object? My first idea was to store all created MockT instances in a static container from the constructor, then delete them from the container from the destructor. This would work if the object were created in a different method than where it is used, like this:
myClassUnderTest.createTheObject();
MOCK_EXPECT(MockT::findMyObject().doSomething);
myClassUnderTest.useTheObject();
But for this I would need to modify the interface of my class, and I really don't want to do that. Is there anything else I can do?
You can use Typemock Isolator++ if you don't want to modify your interface or introduce extra indirection.
template <typename T>
class MyClass
{
public:
void someMethod()
{
T object;
object.doSomething();
}
};
class RealType //RealType is the actual production type, no injection needed
{
public:
void doSomething(){}
};
Since T is created inside someMethod (inside under test method), we need to fake the T's ctor.
FAKE_ALL does just that. The behavior set on fakeRealType will apply to all RealType instances created in runtime. The default FAKE_ALL behavior is a recursive fake, meaning that all the fakes's methods are faked and will return fake objects. You can also manually set any behavior you want on any method.
TEST_CLASS(MyTests)
{
public:
TEST_METHOD(Faking_Dependency_And_Asserting_It_Was_Called)
{
RealType* fakeRealType= FAKE_ALL<RealType>();
MyClass<RealType> myClassUnderTest;
myClassUnderTest.someMethod();
ASSERT_WAS_CALLED(fakeRealType->doSomething());
}
};
Typemock fakes are not strict, so you need to write an appropriate assert to make sure that your method was indeed called. You can do it using ASSERT_WAS_CALLED which is also provided by Typemock.
P.S I used MSTest.
You could redirect the doSomething member function to a static one e.g.
struct MockT
{
void doSomething() {
soSomethingS();
}
MOCK_STATIC_FUNCTION( doSomethingS, 0, void(), doSomething )
};
Then your test would be
BOOST_AUTO_TEST_CASE(testSomeMethod) {
MyClass<MockT> myClassUnderTest;
MOCK_EXPECT(MockT::doSomething).once();
myClassUnderTest.someMethod();
}
If needed you can test the construction and destruction of the object instance, but it likely doesn't bring much more to your test.
I found that the best is to use a shared pointer for the member. It is unfortunate that I have to use an extra indirection just because of the unit test, but at least it works well.
template <typename T, typename TFactory>
class MyClass {
...
void someMethod() {
std::shared_ptr<T> object = factory();
object->doSomething();
}
...
TFactory factory;
};
Then in the test it looks something like this:
BOOST_AUTO_TEST_CASE(testSomeMethod) {
std::shared_ptr<T> mockT;
MockTFactory factory(mockT);
MyClass<MockT, MockTFactory> myClassUnderTest(factory);
MOCK_EXPECT(mockT->doSomething).once();
myClassUnderTest.someMethod();
}

Run typed_test for only one of specified types

Let's suppose i've written a code like this.
template <typename T>
class FooTest : public testing::Test
{
//class body
};
typedef ::testing::Types<int, float/*, and few more*/> TestTypes;
TYPED_TEST_CASE(FooTest, TestTypes);
TYPED_TEST(FooTest, test1)
{
//...
}
TYPED_TEST(FooTest, test2)
{
//...;
}
Is there any possibility to run, for example second test, for only one of data types specified in TestTypes and avoid any code duplication?
You should be able to do this by creating a second test class using inheiritance.
This is similar to the approaches on two faq entries:
Can I derive a test fixture from another?
I have several test cases which share the same logic...
In the code outline below, I have separate the types into two disjoint sets.
template <typename T>
class FooTest : public testing::Test
{
//class body
};
// TestTypes only contains some of the types as before
// in this example, floating point types are tested only with FooTest.
typedef ::testing::Types<float, double, /*, and few more*/> TestTypes;
TYPED_TEST_CASE(FooTest, TestTypes);
TYPED_TEST(FooTest, test1)
{
//...
}
// Optional, but could allow you to reuse test constructor
// and SetUp/TearDown functions
template <typename T>
class ExtendedFooTest : public FooTest<T>
{}
// And integral types are given extended tests
typedef ::testing::Types<int, unsigned int, and few more*/> ExtendedFooTypes;
TYPED_TEST_CASE(FooTest, ExtendedFooTypes); // repeat the tests above
TYPED_TEST_CASE(ExtendedFooTest, ExtendedFooTypes); // Plus add new tests.
TYPED_TEST(ExtendedFooTest, test2)
{
//...;
}