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