In C++, returning objects by value typically means creating a new instance of an object on the stack. This requires either a copy constructor or compiler-generated code to handle the object’s copying.
However, if your class lacks a copy constructor, operations like returning objects by value from a mocked method were not feasible—until now.
Traditionally, when unit testing with Typemock Isolator++, mocking methods that return objects by value required a copy constructor. Without it, returning such objects in a mocked scenario was impossible due to the need for object copying onto the stack.
The New Typemock Isolator++ Feature
With Typemock Isolator++ 4.3.0, you can now mock methods that return objects by value—even if the class doesn’t have a copy constructor. This new capability removes previous limitations, enabling seamless testing of classes that enforce modern C++ practices, such as move semantics or restricted copying.
This feature is essential for testing methods in legacy code and modern designs alike, allowing you to maintain your class design while fully utilizing return-by-value operations in your tests.
Example Test
Here’s a unit test demonstrating how Typemock Isolator++ can return a class without a copy constructor by value:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class CheckByValueWithoutCopyCtor { public: CheckByValueWithoutCopyCtor() { val = -1; }; CheckByValueWithoutCopyCtor(int i) { val = i; }; int val; }; class ReturnByValue { public: CheckByValueWithoutCopyCtor UseCheckByValueWithoutCopyCtor() { return CheckByValueWithoutCopyCtor(1); } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
TEST_METHOD(ReturnObjByVal_WithByVal_NoCopyCtor_Works) { //Arrange ReturnByValue underTest; CheckByValueWithoutCopyCtor classWithNoCopyCtor(3); //Note: Use BY_VAL WHEN_CALLED(underTest.UseCheckByValueWithoutCopyCtor()). Return(BY_VAL(classWithNoCopyCtor)); //Act auto res = underTest.UseCheckByValueWithoutCopyCtor(); //Assert Assert::AreEqual(3, res.val); } |
Typemock Isolator++ continues to support modern C++ features, ensuring that your tests can handle even the most complex object lifecycle scenarios without sacrificing test coverage or code design integrity.