new keyword in C will throw an exception if insufficient memory but below code trying to return "NO_MEMORY" when new failed. This is bad because it will raise std::bad_alloc exception .
I am writing a unit test(gtest). How to create a scenario to catch this problem.
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);
}
CodePudding user response:
Have you looked into EXPECT_THROW?
Below is one way of testing the scenario you described.
I slightly modified your base class to get a size variable to allocate a large amount of memory which may or may not fail. This allows demoing the two possible scenarios.
In practice, you can keep your own base class but still use EXPECT_THROW in a similar way.
As the other answer mentions, you could also use a mock class for base to mock the two scenarios.
// https://stackoverflow.com/questions/70925635/gtest-on-new-keyword
#include "gtest/gtest.h"
class base {
public:
base(unsigned long size) {
i = new int[size * size]; // Allocating a high amount of memory.
std::cout << "base\n";
}
int *i;
};
std::string getInstance(base **obj, unsigned long size) {
base *bObject = new base(size);
*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?
}
// The Test: Call getdata(), verify sum.
TEST(Test_CUT, TestGet) {
base *base_obj;
// Simple usage of EXPECT_THROW. This one should THROW.
EXPECT_THROW(getInstance(&base_obj, 1000000000000L), std::bad_alloc);
std::string result1;
// You can put a block of code in it:
EXPECT_THROW({ result1 = getInstance(&base_obj, 1000000000000L); },
std::bad_alloc);
EXPECT_NE(result1, "SUCCESS");
std::string result2;
// This one should NOT throw an exception.
EXPECT_NO_THROW({ result2 = getInstance(&base_obj, 10L); });
EXPECT_EQ(result2, "SUCCESS");
}
Working example here.
CodePudding user response:
First I think you need to catch the exception otherwise your program will never reach the point of returning 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";
}
}
A quick and dirty way for testing this would be to make the constructor (or an overloaded new) to throw std::bad_alloc:
#ifdef UNIT_TESTING
// simulate there is no memory
base::base() { throw std::bad_alloc; }
#else
base::base() { }
#endif
But I guess the proper way would be to use something like mockcpp
Edit: Since your are using gtest you might prefer using Google Mock to mock base with a constructor throwing bad_alloc instead of the dirty substitution of base::base
