I have mock defined as follows:
template<typename T>
class ParseTreeMock : public ParseTreeInterface<T> {
public:
MOCK_METHOD1(fillConfigTree, void(std::string const&));
MOCK_METHOD1_T(getProperty, T(std::string const&));
ParseTreeMock(): parseTree(std::make_unique<pt::ptree>()) {
}
static std::unique_ptr<ParseTreeInterface<T>> getDefaultTree() {
return std::make_unique<ParseTreeMock<T>>();
}
private:
std::unique_ptr<pt::ptree> parseTree;
};
which is created later in test case:
class ConfigTest : public ::testing::Test {
protected:
std::unique_ptr<ParseTreeInterface<std::string>> treeMock;
virtual void SetUp() {
treeMock = ParseTreeMock<std::string>::getDefaultTree();
}
};
And I want to set return specific value on getProperty method:
EXPECT_CALL(*treeMock, getProperty("miniReaderConfig.cacheConfig.cacheOnOff")).willOnce(Return(false));
I get error:
In file included from ./lib/googletest/googlemock/include/gmock/gmock-generated-function-mockers.h:43:0,
from ./lib/googletest/googlemock/include/gmock/gmock.h:61,
from ./test/UT/Mocks/ParseTreeMock.hpp:2,
from test/UT/Configuration/ConfigTest.cpp:1:
test/UT/Configuration/ConfigTest.cpp: In member function ‘virtual void ConfigTest_CreateConfigurationWithoutErrors_Test::TestBody()’:
./lib/googletest/googlemock/include/gmock/gmock-spec-builders.h:1844:12: error: ‘class miniReader::Configuration::ParseTreeInterface<std::__cxx11::basic_string<char> >’ has no member named ‘gmock_getProperty’; did you mean ‘getProperty’?
((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call)
Any solution with explanation of error appreciated.
The treeMock variable needs to be of type std::unique_ptr<ParseTreeMock<std::string>>, and then static method needs to look like this
static std::unique_ptr<ParseTreeMock<T>> getDefaultTree()
{
return std::make_unique<ParseTreeMock<T>>();
}
Typically you instantiate a class that implements an interface in your test and then pass the instance to the class that you are testing, and with EXPECT_CALLs you make sure that the class you are testing calls the callbacks on your mock object.
Not related to the error you got, but WillOnce needs to be spelled with the first letter capitalized. Also, since you set the template variable to std::string, the EXPECT_CALL can't expect that a boolean is returned.
This compiles for me:
namespace pt { struct ptree {};}
template<typename T>
class ParseTreeInterface
{
public:
virtual void fillConfigTree(std::string const&) = 0;
virtual T getProperty(std::string const&) = 0;
};
template<typename T>
class ParseTreeMock : public ParseTreeInterface<T> {
public:
MOCK_METHOD1(fillConfigTree, void(std::string const&));
MOCK_METHOD1_T(getProperty, T(std::string const&));
ParseTreeMock(): parseTree(std::make_unique<pt::ptree>()) {
}
static std::unique_ptr<ParseTreeMock<T>> getDefaultTree()
{
return std::make_unique<ParseTreeMock<T>>();
}
private:
std::unique_ptr<pt::ptree> parseTree;
};
class ConfigTest : public ::testing::Test {
protected:
std::unique_ptr<ParseTreeMock<std::string>> treeMock;
virtual void SetUp() {
treeMock = ParseTreeMock<std::string>::getDefaultTree();
}
};
TEST_F(ConfigTest, test)
{
EXPECT_CALL(*treeMock, getProperty("miniReaderConfig.cacheConfig.cacheOnOff")).WillOnce(::testing::Return(""));
}
Related
I am writing Interface and Invoker class that allows a class to be several type of invoker and several type of interface.
I don't manage to fix ambiguities in compilation when the function have no parameters ( so all versions have same signature ).
I tried to templatize the function so I can specialize when calling, but It still not removing the ambiguities.
I Know there several article here that talk about similar issue, but they are all with a parameter in the method so the signature is different for each specialization which remove the ambiguity.
I wrote a sample project as small as possible to show.
The workaround for the function Invoker::Interfaces is to add a parameter in the function, and they I can call with (IMyInterface*)0 , but this is ugly .
The workaround for the function Invoker::Register, is to static cast the parameter, but with a template it should find automatically the type of the parameter and I shouldn't need that.
Some help would be very grateful. So I could remove those ugly workarounds.
Thanks a lot.
Here the sample code.
template interface base class
template <class INVOKER>
class Interface
{
public:
INVOKER& Invoker() { return *m_invoker; }
private:
template <typename> friend class Invoker;
INVOKER* m_invoker;
};
template Invoker base class:
template <class INTERFACE>
class Invoker
{
public:
template<class I>
void Register(INTERFACE* _interface) { m_interfaces.push_back(_interface); }
void Register(INTERFACE* _interface) { m_interfaces.push_back(_interface); }
std::vector<INTERFACE*> Interfaces() { return m_interfaces; }
std::vector<INTERFACE*> Interfaces(INTERFACE*) { return m_interfaces; }
template<class I>
std::vector<INTERFACE*> Interfaces() { return m_interfaces; }
private:
std::vector<INTERFACE*> m_interfaces;
};
A short as possible of multi inheritance usage:
class DogLover;
class InterfaceDog : public Interface<DogLover>
{
public:
virtual bool AskIfGoodBoy() = 0;
};
class CatLover;
class InterfaceCat : public Interface<CatLover>
{
public:
virtual void Pet() = 0;
};
class DogLover : public Invoker<InterfaceDog> {};
class CatLover : public Invoker<InterfaceCat> {};
class PetLover
: public DogLover
, public CatLover
{
public:
using DogLover::Register;
using DogLover::Interfaces;
using CatLover::Register;
using CatLover::Interfaces;
int Size() { return m_size; }
void DoStuff()
{
for (InterfaceDog* interface : Interfaces((InterfaceDog*)0))
{
interface->AskIfGoodBoy();
}
/*
for (InterfaceCat* interface : Interfaces<InterfaceCat>()) << ambigous
{
interface->Pet();
}*/
}
private:
int m_size = 0;
};
class PetOwner
: public InterfaceCat
, public InterfaceDog
{
//using InterfaceDog::Invoker;
//using InterfaceCat::Invoker;
void Pet() override { /* Invoker().Size(); */}
bool AskIfGoodBoy() override { return true; }
};
Main :
int main()
{
PetLover petLover;
PetOwner petOwner;
//petLover.Register<DogLover>(&petOwner); // << ambigous
//petLover.Register<CatLover>(&petOwner); // << ambigous
petLover.Register(static_cast<InterfaceDog*>(&petOwner));
petLover.Register(static_cast<InterfaceCat*>(&petOwner));
}
Thanks to #fabian (https://stackoverflow.com/users/2991525/fabian)
I forgot the obvious simplest solution :) which it to specify the class which from you want to call the method like this
Interface:
for (InterfaceCat* interface : CatLover::Interfaces())
{
interface->Pet();
}
Register:
petLover.DogLover::Register(&petOwner);
petLover.CatLover::Register(&petOwner);
Invoker:
class PetOwner
: public InterfaceCat
, public InterfaceDog
{
void Pet() override
{
InterfaceDog::Invoker().Size();
}
Here is a simplified example (from gMock Cookbook) of a class template that I want to mock:
class StackInterface {
public:
virtual ~StackInterface();
virtual int GetSize() const {
return 3;
}
};
template<typename Elem>
class MockStack : public StackInterface<Elem> {
public:
MockStack() : StackInterface<Elem>(){};
MOCK_METHOD(int, GetSize, (), (const, override));
};
I'm using it as follows:
class StackTest : public testing::Test {
public:
StackTest() {
mockStack_ = std::make_shared<MockStack<int>>();
}
protected:
std::shared_ptr<MockStack<int>> mockStack_;
};
TEST_F(StackTest, TestGetSize1) {
EXPECT_CALL(*mockStack_, GetSize()).WillRepeatedly(testing::Invoke([&]() -> int { return 5; }));
StackInterface<int> myStack;
auto res = myStack.GetSize();
EXPECT_EQ(res, 5);
}
This test fails because returned value is 3 which is my real function - Why is my mock implementation being ignored? How can I ensure the mock implementation is used?
The GetSize method needs to be called by the mock object. That's mockStack_
template <typename Elem>
class StackInterface {
public:
StackInterface() {}
virtual ~StackInterface() {}
virtual int GetSize() const {
return 3;
}
};
template <typename Elem>
class MockStack : public StackInterface<Elem> {
public:
MockStack() : StackInterface<Elem>() {
ON_CALL(*this, GetSize()).WillByDefault(Return(1)); }
~MockStack() {}
MOCK_METHOD(int, GetSize, (), (const, override));
};
class StackTest : public testing::Test {
public:
StackTest() {
mockStack_ = std::make_shared<MockStack<int>>();
}
protected:
std::shared_ptr<MockStack<int>> mockStack_;
};
TEST_F(StackTest, TestGetSize1) {
EXPECT_CALL(*mockStack_, GetSize()).WillRepeatedly(testing::Invoke([&]() -> int { return 5; }));
EXPECT_EQ(mockStack_->GetSize(), 5);
}
I got three classes. One ClassFactoryBase which looks like this:
class ClassFactoryBase {
public:
virtual ~ClassFactoryBase () = default;
virtual AbstractBase* Create() = 0;
};
I inherit from that class the actual Factory as a template
template <typename Type>
class ClassFactory final : public ClassFactoryBase {
ClassFactory (/*ClassFactoryBase& Factory*/); //Idea to automatically add them
~ClassFactory () = default;
AbstractBase* Create() override; //returns new Type
};
And ofc I implemented the Factory itself:
class ClassTypeFactory {
public:
template<typename Type>
void AddFactory(ClassFactoryBase& ClassFactory); // inserts ClassFactory into the map m_Factories
AbstractBase* Create(const std::string& ClassType);
private:
std::map<std::string, ClassFactoryBase&> m_Factories;
};
If I implement it like this I have to add to this Inside of my main.cpp
ClassTypeFactory class_type_factory;
ClassFactory<TopClass> top_state_factory(&class_type_factory);
class_type_factory.AddFactory<TopClass>(top_class_factory); // leave this out
This works just fine but I wonder if I could implement it in a way that I can leave out the last line. I think it should work because they both use the same template parameter.
I tried to give my ClassFactory a reference to a Factory and than call the AddFactory Method in there but I cant make it work. I always get inaccessible errors.
You just have to do it in correct order. Following modified version of your example (using smart pointer):
// Your objects to create:
struct AbstractBase
{
virtual ~AbstractBase () = default;
// ...
};
struct Derived : AbstractBase
{
// ...
};
// Your abstract factory
class ClassFactoryBase {
public:
virtual ~ClassFactoryBase () = default;
virtual std::unique_ptr<AbstractBase> Create() = 0;
};
// Your factory collection
class ClassTypeFactory {
public:
void AddFactory(const std::string& name, ClassFactoryBase& factory) { m_Factories.emplace(name, std::ref(factory)); }
std::unique_ptr<AbstractBase> Create(const std::string& name)
{
return m_Factories.at(name).get().Create();
}
private:
std::map<std::string, std::reference_wrapper<ClassFactoryBase>> m_Factories;
};
// Your real factory
template <typename Type>
class ClassFactory final : public ClassFactoryBase {
public:
ClassFactory(const std::string& name, ClassTypeFactory& factory) { factory.AddFactory(name, *this); }
std::unique_ptr<AbstractBase> Create() override { return std::make_unique<Type>(); }
};
And then usage:
ClassTypeFactory class_type_factory;
ClassFactory<Derived> top_state_factory("TopClass", class_type_factory);
auto ptr = class_type_factory.Create("TopClass");
Demo
I am trying for a while now to Unit-test my Factory with gmock/gtest, but I can't get my test to actually use the mock-object I want to test and at this point I feel like I'm doing something fundamentally wrong.
I have the following architecture (headers excluded)
with a Factory and ObjectFactory:
class IObject
{
public:
virtual ~IObject() {};
virtual void objectFunction(int someValue) = 0;
};
using ObjectPtr = std::unique_ptr<IObject>;
class IObjectFactory
{
public:
virtual ~IObjectFactory() {};
virtual std::unique_ptr<IObject> create() = 0;
};
using ObjectFactoryPtr = std::unique_ptr<IObjectFactory>;
The ObjectFactory Class returns an instance of the Object Class like this:
ObjectFactory.h
class ObjectFactory : public IObjectFactory
{
public:
ObjectFactory() {};
~ObjectFactory() override {};
std::unique_ptr<IObject> create() override
{
return std::make_unique<Object>();
}
};
I also have the Collection Class
ICollection.h
class ICollection
{
public:
virtual ~ICollection() {};
virtual void someFunction(int value) = 0;
};
Collection.h
class Collection : public ICollection
{
public:
Collection(IParameter *parameter, double& slider, FilterFactoryPtr&& filterFactory);
~Collection() override;
private:
ObjectFactoryPtr objectFactory_ {};
ObjectPtr object_ {};
The Collection Class gets the ObjectFactory injected in it's constructor and creates an instance of Object with it in the constructor like this:
Collection.cpp
Collection::Collection(IParameter *parameter, double aValue, ObjectFactoryPtr&& objectFactory)
: objectFactory (std::move(objectFactory))
{
object_ = objectFactory->create();
}
finally, in a function call of the Collection Class, objectFunction from the Object Class is called.
In order to test the behavior of Object, ObjectFactory and Collection I wrote some mocks like this:
ObjectMock.h
class ObjectMock : public IMock
{
public:
virtual ~ObjectMock() {}
MOCK_METHOD1(objectFunction, void(int someValue));
};
ObjectFactoryMock.h
class ObjectFactoryMock : public IObjectFactory
{
public:
virtual ~ObjectFactoryMock() {}
virtual std::unique_ptr<IObject> create()
{
return std::unique_ptr<dearvrDir::IObject>(createProxy());
}
MOCK_METHOD0(createProxy, IObject* ());
}
ParameterMock.h
class ParameterMock : public IParameterMock
{
public:
virtual ~ParameterMock() {}
MOCK_CONST_METHOD0(getValue, double());
}
finally, I want run the following test to validate the create() call of the objectFactory object:
class UnitTest_CollectionTestCase : public ::testing::Test
{
protected:
std::unique_ptr<Collection> collection_;
ParameterMock parameterMock_;
};
TEST_F(UnitTest_CollectionTestCase, calls_create_on_factory)
{
double value = 123;
collection_ = std::make_unique<Collection>(¶meterMock_, value, std::make_unique<ObjectFactoryMock>());
auto&& objectFactoryMock = std::make_unique<NiceMock<ObjectFactoryMock>>();
ON_CALL(*objectFactoryMock, create())
.WillByDefault(Return(std::make_unique<Object>));
}
However, instead of test results, I get the following error, hinting towards my Return expectation:
error: no matching function for call to 'ImplicitCast_'
value_(ImplicitCast_(value_before_cast_)) {}
^~~~~~~~~~~~~~~~~~~~~
note: in instantiation of member function 'testing::internal::ReturnAction > (*)()>::Impl, std::__1::default_delete > (*)(), IObject *()>::Impl' requested here
return Action(new Impl(value_));
^
note: in instantiation of function template specialization 'testing::internal::ReturnAction > (*)()>::operator Action' requested here
.WillByDefault(Return(std::make_unique));
I'm kind of hopeless at this point and would be happy to hear any suggestions on the topic.
thanks in advance,
Simon
Turns out I just had to add "ByMove" to my ON_CALL statement, to instruct my mock object not to invoke the copy constructor, which is deleted due to the unique_ptr.
Thus, the statement
ON_CALL(*objectFactoryMock, create())
.WillByDefault(Return(std::make_unique<Object>()));
has to be
ON_CALL(*objectFactoryMock, create())
.WillByDefault(Return(ByMove((std::make_unique<Object>())));
I'm having trouble using template member functions and template variables. The goal is to create an template for an interface which can be inherited and linked to one or more services initialized at runtime. This interface would also pass data to these specialized services (e.g. MyService). For a simpler example, with this code:
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service) {AttachService(*_Service);} //This function does other stuff too.
template <typename T> void AttachService(T _Service) { m_AttachedService<T> = *_Service; }
template <typename T> T AttachedService() { return m_AttachedService; }
protected:
template<typename T> static T m_AttachedService;
class InterfaceListener
{
void Received()
{
int a = 1;
std::string b = "hello";
AttachedService().setA(a);
m_AttachedService.setB(b);
};
};
};
class Service
{
Service();
~Service();
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
MyService();
~MyService();
private:
int A;
std::string B;
protected:
Interface x;
public:
void init() { x.init(this);}
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main();
{
MyService myserv;
myserv.init();
}
I get the following errors:
C2672: 'Interface::AttachedService': no matching overloaded function found
C2783: 'T Interface::AttachedService(void)': could not deduce template argument for 'T'
C2228: left of '.setA' must have class/struct/union
C3245: 'Interface::m_AttachedService': use of a variable template requires template argument list
Any help understanding proper usage of templates would be appreciated!
Let's start with a minimal program that builds and runs without doing anything useful.
#include <string>
class Interface
{
};
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() {}
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
You'll notice that there are few changes from your posted code to get to that baseline.
Interface is empty.
The member functions of Service are in public section. The default constructor and the destructor of Service have an empty implementation.
The default constructor and the destructor of MyService are in the public section of the class and they have empty implementations.
MyService::init() has an empty implementation.
Now we can start adding more code.
I changed MyService::init() to:
void init() { x.init(this); }
With no other changes, I got the following compiler error.
socc.cc: In member function ‘virtual void MyService::init()’:
socc.cc:25:23: error: ‘class Interface’ has no member named ‘init’
void init() { x.init(this);}
Now, Interface needs to be updated with an init function.
I added a dummy implementation to move the process forward.
class Interface
{
public:
template <class T> bool init(T *_Service) { return true; }
};
Time to add something useful to Interface::init(). Changing it to
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
produces the following compiler error, which is not surprising.
socc.cc: In instantiation of ‘bool Interface::init(T*) [with T = MyService]’:
socc.cc:31:32: required from here
socc.cc:8:23: error: ‘AttachService’ was not declared in this scope
AttachService(*_Service);
~~~~~~~~~~~~~^~~~~~~~~~~
Time to add AttachService. Changing Interface to (closing matching what you have)
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = *_Service;
}
protected:
template<typename T> static T m_AttachedService;
};
produces the following compiler error.
socc.cc: In instantiation of ‘void Interface::AttachService(T) [with T = MyService]’:
socc.cc:8:10: required from ‘bool Interface::init(T*) [with T = MyService]’
socc.cc:39:32: required from here
socc.cc:14:33: error: no match for ‘operator*’ (operand type is ‘MyService’)
m_AttachedService<T> = *_Service;
^~~~~~~~~
That makes sense. In AttachServie, _Service is not a pointer.
Changing Inteface::AttachService to:
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
makes the compiler error go away but there is a linker error.
:socc.cc:(.rdata$.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE[.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE]+0x0): undefined reference to `Interface::m_AttachedService<MyService>'
collect2: error: ld returned 1 exit status
That makes sense since we have not defined the static member variable.
Adding the following line
template<typename T> T Interface::m_AttachedService;
right after definition of Interface takes care of the linker error.
The following is the next version of the complete program that builds successfully and runs even though it still doesn't do anything useful.
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
protected:
template<typename T> static T m_AttachedService;
};
template<typename T> T Interface::m_AttachedService;
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() { x.init(this); }
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
Time to add your version of the AttachedService to Interface
template <typename T> T AttachedService() { return m_AttachedService; }
That produces the following compiler error.
socc.cc: In member function ‘T Interface::AttachedService()’:
socc.cc:17:73: error: missing template arguments before ‘;’ token
template <typename T> T AttachedService() { return m_AttachedService; }
That makes sense since m_AttachedService is not a member variable but a member variable template.
Changing that to
template <typename T> T AttachedService() { return m_AttachedService<T>; }
removes that error.
Now the final piece in Interface. The nested class InterfaceListener that you have posted does sound right. You have
class InterfaceListener
{
void Received()
{
int a = 1;
std::string b = "hello";
AttachedService().setA(a);
m_AttachedService.setB(b);
};
};
Problems in that class:
AttachedService() is not right since it a member function template. You have to provide a template parameter to use it.
Also, AttachedService() is not a static member function. You need an instance of Interface to make that call.
m_AttachedService is not a member variable. It is a member variable template. You have to provide a template parameter to use it.
The functions setA() and setB() are valid only if the template parameter is MyService. It does not make sense to have code in that function that is specific to a type.
I'll leave it for you to ponder over how you intend to use InterfaceListener and define its functions appropriately. Until then the following program builds and runs for me.
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
template <typename T> T AttachedService() { return m_AttachedService<T>; }
protected:
template<typename T> static T m_AttachedService;
};
template<typename T> T Interface::m_AttachedService;
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() { x.init(this); }
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}