Search code examples
c++vectormockinggoogletest

How to mock a vector of an arbitrary size?


I've defined a class that accepts a vector as a constructor input parameter and provides a method that uses vector's size() function:

class Foo {
  vector<int> storedVector;

  public:
    explicit Foo(vector<int>);
    bool isSizeGreaterThanInt();
}

Foo::Foo(vector<int> inputVector) : storedVector(std::move(inputVector)) {  }

bool Foo::isSizeGreaterThanInt()
{
  if (storedVector.size() > INT32_MAX) { return true; }

  return false;
}

Now I would like to test the isSizeGreaterThanInt() method of this class. As part of that test I want to also validate that the size() call inside of the implementation returns the size() of the vector passed into the constructor and not some other vector/some other size.

I'm using gtest and gmock as my testing and mocking framework respectively.

All my attempts to create a mock of vector<int> which mocks the size() function to return a specific value seem to fail, my latest version of the mock is as follows:

template <typename VectorValueType>
class MockVector : public std::vector<VectorValueType> {
  public:
    MOCK_CONST_METHOD0_T(size, size_t());
};

TEST(Test,TestCase)
{
  size_t fakeSize = static_cast<size_t>(INT32_MAX) + 1;
  MockVector<int> mockVector;
  EXPECT_CALL(mockVector, size()).WillRepeatedly(testing::Return(fakeSize));

  size_t testSize = mockVector.size(); // here the value is correct

  Foo foo (mockVector);

  // if I debug here and check the size of the vector now stored in foo - it's 0.

  ASSERT_EQ(true, foo.isSizeGreaterThanInt());
}

I had concerns about std::move and move behavior so I tried passing inputVector by reference, tried passing pointers, tried storing vector<int>& storedVector instead of having a value member... nothing worked.

Is what I'm trying to do possible? What am I doing wrong?

Update

One of the commenters suggested it happens due to splicing of the MockVector type into vector<int>, and when it's spliced the mocked methods are no longer called... but still, how should I go about mocking the vector? There is no interface for vector<> in C++ STL, so I can't make that a parameter to the constructor...

Update 2

As suggested in one of the answers, yes, I can add a getSize() to Foo and mock that... But it changes Foo's contract and I'd prefer not to do that. Furthermore, if I was willing to do that, I still would need to mock my vector to test the getSize() behavior to ensure that getSize() truly returns the size() of the vector and not some other value. Basically, doing that is just moving the same problem to a different place.

Update 3

Yes, theoretically I can create a vector in my test, just pass it in and not mock it. The issue here is that to test the specific behavior described above I'll need to create a vector with (INT32_MAX + 1) elements in it, which is prohibitively expensive (resources/time/memory) for the test.


Solution

  • You cannot mock methods of std::vector, because mocking system in GoogleTest is based on polymorphism and std::vector is not prepared for use in polymorphism - none of its methods are virtual. Since size() method is not virtual, the mock implementation will never be called and GoogleMock cannot register that call or execute actions.

    The only way to test that would be to pass the vector of size INT32_MAX to the tested class (perhaps this test should be disabled by default and only enabled in CI envireonment) or to create a wrapper for std::vector which will have virtual methods in its interface.