谷歌测试和谷歌模拟中的模拟变量函数



我是Google测试的新手,我正试图为一个返回void且不带参数的函数编写一个单元测试,但该函数有一个检查结构值的if条件,我需要覆盖这一行,其中结构元素的任何值都是0,这样就会调用panic函数来打印错误消息。据我所知,panic是可变函数,可变函数不能在谷歌测试中被嘲笑,所以如果我在测试中强制使用一些值来测试函数的负路径,我应该如何测试会调用panic函数?来源.cpp

void foo (){ 
if (
mystruct.version==0||
mystruct.size==0||
mystruct.start==0
)
panic("error message");
// some function calls
}

在我的测试文件gtest_mytest.cpp中,我包括了我的source.cpp,因为它也有一些静态函数,我想在未来测试,我在那里复制了恐慌函数定义,如下所示,

#include "source.cpp"
void panic(const char *fmt, ...)
{
va_list v;
va_start(v, fmt);
vprintf(fmt, v);
va_end(v);
putchar('n');
exit(1);
}
TEST(myTest,fooTestNegative)
{
myStruct teststr;
teststr.version = 0;
foo();
// MY Question is here how to expect that now Panic should be called!
}

首先,您应该编写一个包装器来模拟这里描述的自由函数

其次,您应该能够使用这样的方法作为模拟可变函数的变通方法。

附带说明:在代码中包含cpp文件是非常罕见的。常见的约定是只将函数的签名放在.h文件中,然后将其包含在.cpp文件中。

下面是我使用上述方法的实现:

#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
#include <memory>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using ::testing::_;
class PanicWrapperInterface {
public:
virtual void panic(std::string fmt) = 0;
};
// Production wrapper.
class PanicWrapper : public PanicWrapperInterface {
public:
void panic(std::string fmt) {}
};
// Mock wrapper.
class MockPanicWrapper : public PanicWrapperInterface {
public:
MOCK_METHOD(void, panic, (const std::string), ());
};
// Variadic function.
// The panic function should take an extra parameter mock_interface.
// Alternatively, the extra parameter can be converted to a global variable.
extern "C" {
void panic(PanicWrapperInterface *mock_interface, const char *fmt, ...) {
if (dynamic_cast<PanicWrapper *>(mock_interface)) {
// The production implementation of panic function. Used only for
// production, not for testing.
va_list v;
va_start(v, fmt);
vprintf(fmt, v);
va_end(v);
putchar('n');
} else {
// The mock implementation of panic function. Used only for testing.
std::string non_variadic("");
if (fmt != NULL) {
va_list args;
va_start(args, fmt);
// Get length of fmt including arguments
int nr = vsnprintf(NULL, 0, fmt, args);
va_end(args);
char buffer[nr + 1];
va_start(args, fmt);
vsnprintf(buffer, nr + 1, fmt, args);
va_end(args);
non_variadic = std::string(buffer);
}
mock_interface->panic(non_variadic);
}
}
}
// The foo function should take an extra parameter mock_interface.
// Alternatively, the extra parameter can be converted to a global variable.
void foo(PanicWrapperInterface *mock_interface, bool some_condition) {
if (some_condition) {
panic(mock_interface, "error message");
}
}
TEST(Panic, isCalled) {
MockPanicWrapper mock_interface;
EXPECT_CALL(mock_interface, panic(_)).Times(1);
foo(&mock_interface, /*some_condition=*/true);
}
TEST(Panic, isNotCalled) {
MockPanicWrapper mock_interface;
EXPECT_CALL(mock_interface, panic(_)).Times(0);
foo(&mock_interface, /*some_condition=*/false);
}
TEST(Panic, productionWrapperWorksCorrectly) {
// Use the production wrapper
PanicWrapper panic_wrapper;
testing::internal::CaptureStdout();
// This should print "error message" in the output.
foo(&panic_wrapper, /*some_condition=*/true);
std::string output = testing::internal::GetCapturedStdout();
EXPECT_EQ(output, "error messagen");
}

请在此处查看实际示例:https://godbolt.org/z/xn36Y45eW

请注意,或者,即使不转换为non_variadic:,也可以简化上述代码以使其工作


class PanicWrapperInterface {
public:
virtual void DummyPanic() = 0;
};
// Production wrapper.
class PanicWrapper : public PanicWrapperInterface {
public:
void DummyPanic() {}
};
// Mock wrapper.
class MockPanicWrapper : public PanicWrapperInterface {
public:
MOCK_METHOD(void, DummyPanic, (), ());
};
// Variadic function.
// The panic function should take an extra parameter mock_interface.
// Alternatively, the extra parameter can be converted to a global variable.
extern "C" {
void panic(PanicWrapperInterface *mock_interface, const char *fmt, ...) {
if (dynamic_cast<PanicWrapper *>(mock_interface)) {
// The production implementation of panic function. Used only for
// production, not for testing.
va_list v;
va_start(v, fmt);
vprintf(fmt, v);
va_end(v);
putchar('n');
} else {
mock_interface->DummyPanic();
}
}
}
// The foo function should take an extra parameter mock_interface.
// Alternatively, the extra parameter can be converted to a global variable.
void foo(PanicWrapperInterface *mock_interface, bool some_condition) {
if (some_condition) {
panic(mock_interface, "error message");
}
}
TEST(Panic, isCalled) {
MockPanicWrapper mock_interface;
EXPECT_CALL(mock_interface, DummyPanic()).Times(1);
foo(&mock_interface, /*some_condition=*/true);
}
TEST(Panic, isNotCalled) {
MockPanicWrapper mock_interface;
EXPECT_CALL(mock_interface, DummyPanic()).Times(0);
foo(&mock_interface, /*some_condition=*/false);
}
TEST(Panic, productionWrapperWorksCorrectly) {
// Use the production wrapper
PanicWrapper panic_wrapper;
testing::internal::CaptureStdout();
// This should print "error message" in the output.
foo(&panic_wrapper, /*some_condition=*/true);
std::string output = testing::internal::GetCapturedStdout();
EXPECT_EQ(output, "error messagen");
}

此处的示例:https://godbolt.org/z/73vvrxcbo

相关内容

  • 没有找到相关文章

最新更新