Home > Mobile >  Gtest on new keyword
Gtest on new keyword

Time:02-01

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

  •  Tags:  
  • Related