Gtest 新关键字
Gtest on new keyword
如果内存不足,C++ 中的 new 关键字将抛出异常,但下面的代码尝试 return "NO_MEMORY" 当 new 失败时。这很糟糕,因为它会引发 std::bad_alloc 异常。
我正在写一个单元测试(gtest)。如何创建场景来解决这个问题。
class base{
public: base(){
std::cout<<"base\n";
}
};
std::string getInstance(base** obj){
base *bObject = new base();
*obj = bObject; //updated
return (NULL == bObject) ? "NO_MEMORY" : "SUCCESS"; // here is problem if new fail it raise an exception. How to write unit test to catch this?
}
int main()
{
base *base_obj;
getInstance(&base_obj);
}
首先我认为你需要捕获异常否则你的程序永远不会到达返回点 NO_MEMORY
:
std::string getInstance(base **obj) {
try {
if (!obj)
throw std::invalid_argument("");
*obj = new base();
return "SUCCESS";
}
catch (const std::bad_alloc& e) {
return "NO_MEMORY";
}
catch (...) {
return "UNDEFINED_ERROR";
}
}
一种快速而肮脏的测试方法是让构造函数(或重载的 new
)抛出 std::bad_alloc
:
#ifdef UNIT_TESTING
// simulate there is no memory
base::base() { throw std::bad_alloc; }
#else
base::base() { }
#endif
但我想正确的方法是使用 mockcpp
编辑:由于您使用的是 gtest
,因此您可能更喜欢使用 Google Mock 来模拟 base
,构造函数会抛出 bad_alloc
而不是 [= 的肮脏替换18=]
你调查过 EXPECT_THROW
了吗?
如果你不能完全改变你的代码(如果你想使用 gmock,这是必需的),你可以像其他答案建议的那样全局重载 new 运算符。
但是,您应该谨慎地执行此操作,因为此运算符被其他函数使用,包括 google 测试中的函数。
实现此目的的一种方法是使用全局变量,使 new 运算符有条件地抛出。请注意,这不是最安全的方法,特别是如果您的程序使用多线程
下面是使用此方法和全局变量 g_testing
.
测试您描述的场景的一种方法
//
#include "gtest/gtest.h"
// Global variable that indicates we are testing. In this case the global new
// operator throws.
bool g_testing = false;
// Overloading Global new operator
void *operator new(size_t sz) {
void *m = malloc(sz);
if (g_testing) {
throw std::bad_alloc();
}
return m;
}
class base {
public:
base() { std::cout << "base\n"; }
};
std::string getInstance(base **obj) {
base *bObject = new base();
*obj = bObject; // updated
return (NULL == bObject)
? "NO_MEMORY"
: "SUCCESS"; // here is problem if new fail it raise an exception.
// How to write unit test to catch this?
}
TEST(Test_New, Failure) {
base *base_obj;
// Simple usage of EXPECT_THROW. This one should THROW.
g_testing = true;
EXPECT_THROW(getInstance(&base_obj), std::bad_alloc);
g_testing = false;
std::string result1;
// You can put a block of code in it:
g_testing = true;
EXPECT_THROW({ result1 = getInstance(&base_obj); }, std::bad_alloc);
g_testing = false;
EXPECT_NE(result1, "SUCCESS");
}
TEST(Test_New, Success) {
base *base_obj;
std::string result2;
// This one should NOT throw an exception.
EXPECT_NO_THROW({ result2 = getInstance(&base_obj); });
EXPECT_EQ(result2, "SUCCESS");
}
这是您的工作示例:https://godbolt.org/z/xffEoW9Kd
new 关键字将抛出异常,但下面的代码尝试 return "NO_MEMORY" 当 new 失败时。这很糟糕,因为它会引发 std::bad_alloc 异常。
我正在写一个单元测试(gtest)。如何创建场景来解决这个问题。
class base{
public: base(){
std::cout<<"base\n";
}
};
std::string getInstance(base** obj){
base *bObject = new base();
*obj = bObject; //updated
return (NULL == bObject) ? "NO_MEMORY" : "SUCCESS"; // here is problem if new fail it raise an exception. How to write unit test to catch this?
}
int main()
{
base *base_obj;
getInstance(&base_obj);
}
首先我认为你需要捕获异常否则你的程序永远不会到达返回点 NO_MEMORY
:
std::string getInstance(base **obj) {
try {
if (!obj)
throw std::invalid_argument("");
*obj = new base();
return "SUCCESS";
}
catch (const std::bad_alloc& e) {
return "NO_MEMORY";
}
catch (...) {
return "UNDEFINED_ERROR";
}
}
一种快速而肮脏的测试方法是让构造函数(或重载的 new
)抛出 std::bad_alloc
:
#ifdef UNIT_TESTING
// simulate there is no memory
base::base() { throw std::bad_alloc; }
#else
base::base() { }
#endif
但我想正确的方法是使用 mockcpp
编辑:由于您使用的是 gtest
,因此您可能更喜欢使用 Google Mock 来模拟 base
,构造函数会抛出 bad_alloc
而不是 [= 的肮脏替换18=]
你调查过 EXPECT_THROW
了吗?
如果你不能完全改变你的代码(如果你想使用 gmock,这是必需的),你可以像其他答案建议的那样全局重载 new 运算符。
但是,您应该谨慎地执行此操作,因为此运算符被其他函数使用,包括 google 测试中的函数。
实现此目的的一种方法是使用全局变量,使 new 运算符有条件地抛出。请注意,这不是最安全的方法,特别是如果您的程序使用多线程
下面是使用此方法和全局变量 g_testing
.
//
#include "gtest/gtest.h"
// Global variable that indicates we are testing. In this case the global new
// operator throws.
bool g_testing = false;
// Overloading Global new operator
void *operator new(size_t sz) {
void *m = malloc(sz);
if (g_testing) {
throw std::bad_alloc();
}
return m;
}
class base {
public:
base() { std::cout << "base\n"; }
};
std::string getInstance(base **obj) {
base *bObject = new base();
*obj = bObject; // updated
return (NULL == bObject)
? "NO_MEMORY"
: "SUCCESS"; // here is problem if new fail it raise an exception.
// How to write unit test to catch this?
}
TEST(Test_New, Failure) {
base *base_obj;
// Simple usage of EXPECT_THROW. This one should THROW.
g_testing = true;
EXPECT_THROW(getInstance(&base_obj), std::bad_alloc);
g_testing = false;
std::string result1;
// You can put a block of code in it:
g_testing = true;
EXPECT_THROW({ result1 = getInstance(&base_obj); }, std::bad_alloc);
g_testing = false;
EXPECT_NE(result1, "SUCCESS");
}
TEST(Test_New, Success) {
base *base_obj;
std::string result2;
// This one should NOT throw an exception.
EXPECT_NO_THROW({ result2 = getInstance(&base_obj); });
EXPECT_EQ(result2, "SUCCESS");
}
这是您的工作示例:https://godbolt.org/z/xffEoW9Kd