因此,我正在尝试为我的虚拟类函数创建一个模拟宏。
这是带有一个模拟函数的模拟类的示例。 (这按预期工作)
class MockEnvironment : public IEnvironment {
public:
using runType = int(std::string program,
std::vector<std::string> arguments);
MockedFunction<runType> runMock = MockedFunction<runType>("run");
int run(std::string program, std::vector<std::string> arguments) override {
return runMock(program, arguments);
}
// MOCK_METHOD(int, run, (std::string, std::vector<std::string>)); // this is the goal
};
MockedFunction
是带有operator()的类,应在调用函数时调用该类。我的目标是将函数包装在宏中,以便能够模拟任何函数。您可能会看到的问题是,在泛化时,我将需要处理带有未命名参数的函数。
#define MOCK_METHOD(ret, name, args) \
MockedFunction<ret(args)> mocked_##name = \
MockedFunction<ret(args)>(#name); \
ret name##Mock(args) { /* how to solve? */ }
// This would expand to something like
MockedFunction<...> runMock = MockedFunction<...>("run"); // More detailed in above example
int run(std::string, std::vector<std::string>) override {
return runMock(/*how to forward the arguments when they do not have names?*/)
}
我曾考虑过使用某种可变文本模板,但是还没有找到任何使它工作的方法。我也曾尝试阅读谷歌的模拟实现,但我很难看到他们如何解决它。所以我的问题很简单。如何将
run
中参数的内容移动到要调用的函数?我最多可以使用c++ 17。我确实意识到,如果在宏中指定需要多少个参数,会更容易,但是,如果可以解决更一般的示例,那将是最佳选择。
编辑:
如果我事先知道参数的数量,这是我想出的最好的方法。
#define INTERNAL_MOCK_METHOD_COMMON(ret, name, args) \
using name##T = ret(args); \
unittest::MockedFunction<ret(args)> mock_##name = \
unittest::MockedFunction<ret(args)>(#name);
#define MOCK_METHOD(ret, name) \
INTERNAL_MOCK_METHOD_COMMON(ret, name, ()) \
ret name() { \
return mock_##name(); \
}
#define MOCK_METHOD1(ret, name, args) \
INTERNAL_MOCK_METHOD_COMMON(ret, name, args) \
ret name(typename unittest::MockedFunction<name##T>::ArgT<0>::type a) { \
return mock_##name(a); \
}
#define MOCK_METHOD2(ret, name, args) \
INTERNAL_MOCK_METHOD_COMMON(ret, name, args) \
ret name(typename unittest::MockedFunction<name##T>::ArgT<0>::type a, \
typename unittest::MockedFunction<name##T>::ArgT<1>::type b) { \
return mock_##name(a, b); \
}
// ...
template <typename T>
class MockedFunction {};
template <typename ReturnT, typename... ArgsT>
class MockedFunction<ReturnT(ArgsT...)> {
public:
// Return argument type at the specified index
template <int i>
struct ArgT {
using type = typename std::tuple_element_t<i, std::tuple<ArgsT...>>;
};
然后可以像这样使用
class IObject {
public:
virtual int update() = 0;
virtual void setValue(int) = 0;
};
class MockObject : public IObject {
public:
MOCK_METHOD(int, update);
MOCK_METHOD1(void, setValue, (int));
};
需要说明的是:不必用数字指定参数的数量会很好。
最佳答案
您不能使用未命名的参数。您可以考虑命名它们,也许像这样:
#define MOCK_METHOD(ret, name, args, names) \
MockedFunction<ret(args)> mocked_##name = \
MockedFunction<ret(args)>(#name); \
ret name##Mock(args) { return runMock names; }
MOCK_METHOD(int, run, (std::string s, std::vector<std::string> v), (s, v));
关于c++ - 如何转发未命名的函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64087151/