GoogleMock - Leaked mock objects due to cross-referencing mock classes - c++

I have two classes, Server and Client, each with their own mock class and has a getClients and getServer method respectively (the actual classes are much bigger, but this is the minimal case).
I want to add a variable in the MockServer that's returned by the getClients method, allowing me to modify this variable in my tests whenever appropriate (note the clients variable).
While this works, it will cause the two mock objects to keep each other alive, each keeping a shared_ptr reference to the other, causing the test to leak objects.
Please, look at the example provided below.
Question: How can I modify the Mock Classes, without modifying the interfaces or the create functions, to prevent leaked mock objects while preserving the clients variable?
#include <gmock/gmock.h>
#include <gtest/gtest.h>
struct Client;
struct Server
{
virtual const std::vector<std::shared_ptr<Client>>& getClients() = 0;
};
struct Client
{
virtual std::shared_ptr<Server> getServer() = 0;
};
struct MockServer : virtual Server
{
MOCK_METHOD0(getClients, const std::vector<std::shared_ptr<Client>>&());
std::vector<std::shared_ptr<Client>> clients; // I want to add this variable...
protected:
MockServer()
{
ON_CALL(*this, getClients()).WillByDefault(testing::ReturnRef(this->clients)); // ...and return it whenever getClients is called.
}
~MockServer()
{
clients.clear(); // This doesn't help...
std::cout << __func__ << " - This is never printed." << std::endl;
}
public:
static std::shared_ptr<MockServer> create()
{
return std::make_shared<testing::NiceMock<MockServer>>();
}
};
struct MockClient : virtual Client
{
MOCK_METHOD0(getServer, std::shared_ptr<Server>());
protected:
MockClient(std::shared_ptr<Server> server)
{
ON_CALL(*this, getServer()).WillByDefault(testing::Return(server));
}
~MockClient()
{
std::cout << __func__ << " - This is never printed." << std::endl;
}
public:
static std::shared_ptr<MockClient> create(std::shared_ptr<Server> server)
{
return std::make_shared<testing::NiceMock<MockClient>>(server);
}
};
TEST(ExampleOfLeak, testLeakedMockObjects)
{
auto server = MockServer::create();
auto client1 = MockClient::create(server);
auto client2 = MockClient::create(server);
EXPECT_EQ(server, client1->getServer());
EXPECT_EQ(server, client2->getServer());
EXPECT_TRUE(server->getClients().empty());
server->clients.push_back(client1); // This causes leaked mock objects!
server->clients.push_back(client2); // And this too...
EXPECT_EQ(client1, server->getClients().front());
EXPECT_EQ(client2, server->getClients().back());
// server->clients.clear(); // This prevents mock objects from leaking, but doing this manually everywhere is highly unfeasible.
}
Result:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from ExampleOfLeak
[ RUN ] ExampleOfLeak.testLeakedMockObjects
[ OK ] ExampleOfLeak.testLeakedMockObjects (0 ms)
[----------] 1 test from ExampleOfLeak (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
foo.cc:43: ERROR: this mock object (used in test ExampleOfLeak.testLeakedMockObjects) should be deleted but never is. Its address is #0x2fc3170.
foo.cc:43: ERROR: this mock object (used in test ExampleOfLeak.testLeakedMockObjects) should be deleted but never is. Its address is #0x2fcbcb0.
foo.cc:22: ERROR: this mock object (used in test ExampleOfLeak.testLeakedMockObjects) should be deleted but never is. Its address is #0x2fd6570.
ERROR: 3 leaked mock objects found at program exit.

It's possible to convert a weak_ptr into a shared_ptr using the lock() method.
This way you can store a weak_ptr in you mock class and later convert it.
Though do be careful and make sure the weak_ptr hasn't expired().
#include <gmock/gmock.h>
#include <gtest/gtest.h>
struct Client;
struct Server
{
virtual const std::vector<std::shared_ptr<Client>>& getClients() = 0;
};
struct Client
{
virtual std::shared_ptr<Server> getServer() = 0;
};
struct MockServer : virtual Server
{
MOCK_METHOD0(getClients, const std::vector<std::shared_ptr<Client>>&());
std::vector<std::shared_ptr<Client>> clients;
protected:
MockServer()
{
ON_CALL(*this, getClients()).WillByDefault(testing::ReturnRef(this->clients));
}
~MockServer()
{
clients.clear();
std::cout << __func__ << " - This is printed." << std::endl;
}
public:
static std::shared_ptr<MockServer> create()
{
return std::make_shared<testing::NiceMock<MockServer>>();
}
};
ACTION_P(ReturnWeakToShared, wp)
{
bool isWeakPtrExpired = wp.expired();
EXPECT_FALSE(isWeakPtrExpired) << "Dangling pointer.";
return wp.lock();
}
struct MockClient : virtual Client
{
MOCK_METHOD0(getServer, std::shared_ptr<Server>());
std::weak_ptr<Server> server;
protected:
MockClient(std::shared_ptr<Server> server)
{
this->server = server;
ON_CALL(*this, getServer()).WillByDefault(ReturnWeakToShared(this->server));
}
~MockClient()
{
std::cout << __func__ << " - This is printed." << std::endl;
}
public:
static std::shared_ptr<MockClient> create(std::shared_ptr<Server> server)
{
return std::make_shared<testing::NiceMock<MockClient>>(server);
}
};
TEST(ExampleOfLeak, testLeakedMockObjects)
{
auto server = MockServer::create();
auto client1 = MockClient::create(server);
auto client2 = MockClient::create(server);
EXPECT_EQ(server, client1->getServer());
EXPECT_EQ(server, client2->getServer());
EXPECT_TRUE(server->getClients().empty());
server->clients.push_back(client1);
server->clients.push_back(client2);
EXPECT_EQ(client1, server->getClients().front());
EXPECT_EQ(client2, server->getClients().back());
}

the two mock objects to keep each other alive
One of them definitely should use a weak reference to the other.
For example
#include <gmock/gmock.h>
#include <gtest/gtest.h>
struct Client;
struct Server
{
virtual const std::vector<std::weak_ptr<Client>>& getClients() = 0;
};
struct Client
{
virtual std::shared_ptr<Server> getServer() = 0;
};
struct MockServer : virtual Server
{
MOCK_METHOD0(getClients, const std::vector<std::weak_ptr<Client>>&());
std::vector<std::weak_ptr<Client>> clients; // I want to add this variable...
protected:
MockServer()
{
ON_CALL(*this, getClients()).WillByDefault(testing::ReturnRef(this->clients)); // ...and return it whenever getClients is called.
}
~MockServer()
{
clients.clear(); // This doesn't help...
std::cout << __func__ << " - This is never printed." << std::endl;
}
public:
static std::shared_ptr<MockServer> create()
{
return std::make_shared<testing::NiceMock<MockServer>>();
}
};
struct MockClient : virtual Client
{
MOCK_METHOD0(getServer, std::shared_ptr<Server>());
protected:
MockClient(std::shared_ptr<Server> server)
{
ON_CALL(*this, getServer()).WillByDefault(testing::Return(server));
}
~MockClient()
{
std::cout << __func__ << " - This is never printed." << std::endl;
}
public:
static std::shared_ptr<MockClient> create(std::shared_ptr<Server> server)
{
return std::make_shared<testing::NiceMock<MockClient>>(server);
}
};
TEST(ExampleOfLeak, testLeakedMockObjects)
{
auto server = MockServer::create();
auto client1 = MockClient::create(server);
auto client2 = MockClient::create(server);
EXPECT_EQ(server, client1->getServer());
EXPECT_EQ(server, client2->getServer());
EXPECT_TRUE(server->getClients().empty());
server->clients.push_back(client1); // This causes leaked mock objects!
server->clients.push_back(client2); // And this too...
EXPECT_EQ(client1, server->getClients().front().lock());
EXPECT_EQ(client2, server->getClients().back().lock());
// server->clients.clear(); // This prevents mock objects from leaking, but doing this manually everywhere is highly unfeasible.
}
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from ExampleOfLeak
[ RUN ] ExampleOfLeak.testLeakedMockObjects
~MockClient - This is never printed.
~MockClient - This is never printed.
~MockServer - This is never printed.
[ OK ] ExampleOfLeak.testLeakedMockObjects (0 ms)
[----------] 1 test from ExampleOfLeak (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.

Related

Modify data inside thread

I am writing unit tests for one of the classes I want to test. Function infFooLoop() what I want to test is executed in endless loop (request to stop it comes externally). My problem is I want to change the private variable state_ via setter in setState when function executes in separate thread asynchronously. Some simplified code example is here:
enum class State : int
{
Success = 1,
Failure = 2
};
class Foo
{
private:
State state_{State::Success};
bool stop_flag_{false};
public:
void setState(State state) { state_ = state; }
void infFooLoop(bool &start)
{
while (start)
{
std::cout << "While loop executes \n";
if (state_ == State::Failure)
{
stop_flag_ = true;
}
else if (stop_flag_)
{
std::cout << "Program stopped\n";
// Report error but for this example break
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
};
int main()
{
Foo obj;
bool flag{true};
std::future<void> future = std::async(std::launch::async, [&](){ obj.infFooLoop(flag);});
// Try to change the data:
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// I want to change data for `Failure` so stop_flag condition will be used
obj.setState(State::Failure);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// terminate loop
flag = false;
return 0;
}
state_ will be taken from external component and stop_flag_ is used to handle some corner-case here (in real it wont break the loop, just report error to different component).
I assume infFooLoop executes on a separate thread so I can't just call another function in a different thread to change this data. stop_flag_ is some internal variable used only in this one function so I want to leave it as simple as possible (do not introduce mutexes/atomic in Foo class only for tests). Can you give me some suggestions on what should I do here?

Google Test Returning Garbage Values For Working Operations

I have tested the .decreaseInventory() manually in my main file so I know it works correctly but when I run a google test on it, it fails and gives me an error. How could I fix this?
Player class:
#ifndef PLAYER_H
#define PLAYER_H
#include <iostream>
using namespace std;
class Player
{
int inventory;
public:
Player();
int decreaseInventory(int numOfBeers);
void setInventory(int newInventory);
int getBackOrder();
int getCost();
int getInventory();
bool operator ==(Player& p);
};
Player::Player()
{
cout << " Default Player Constructor\n";
inventory = 12;
backorder = 0;
cost = 0;
orderDelay = 0;
shipmentDeplay = 0;
}
void Player::setInventory(int newInventory)
{
inventory = newInventory;
}
int Player::decreaseInventory(int numOfBeers)
{
inventory = inventory - numOfBeers;
}
int Player::getInventory()
{
return inventory;
}
test.cpp:
#include "gtest/gtest.h"
#include "Player.h"
TEST(playerTest, decreaseInventoryTest ) {
Player p;
int curr_inv = p.getInventory();
EXPECT_EQ(curr_inv-3, p.decreaseInventory(3));
}
Error:
Running main() from gtest_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from playerTest
[ RUN ] playerTest.decreaseInventoryTest
Default Player Constructor
/home/hammad/se-02-team-21/tests.cpp:13: Failure
Expected: curr_inv-3
Which is: 9
To be equal to: p.decreaseInventory(3)
Which is: 1740894128
[ FAILED ] playerTest.decreaseInventoryTest (1 ms)
[----------] 1 test from playerTest (1 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] playerTest.decreaseInventoryTest
1 FAILED TEST
Why does it fail and give a garbage value? I am already using a default constructor and in general it works properly.
You are missing a return value in your decreaseInventory function definition. To fix this, simply return the (modified) value of the inventory member variable:
int Player::decreaseInventory(int numOfBeers)
{
inventory = inventory - numOfBeers;
return inventory; // You need to return the modified value!
}
Your method is:
int Player::decreaseInventory(int numOfBeers)
{
inventory = inventory - numOfBeers;
}
Your test is:
EXPECT_EQ(curr_inv-3, p.decreaseInventory(3));
The macro EXPECT_EQ compares the value returned from p.decreaseInventory(3) with curr_inv-3. The method does not return anything.
Not returning something from a method that is declared to return something is undefined behavior. Your compiler should have warned you about it and your test was successful in the sense that you have a failing test that is caused by a real bug in your code that you now can fix.

Run a repeated test reporting as different tests

I'd like to unit test a function with a set of different inputs and expected outputs.
My function is irrelevant thus I'll instead use an example function which counts english words with the following candidate implementation :
int countEnglishWords( const std::string& text )
{
return 5;
};
The following would be the set of test data. The end of the data is marked by an element with the word "END".
struct TestData {
std::string text;
int englishWords;
};
struct TestData data[] = // Mark end with "END"
{
{ "The car is very fast", 5 },
{ "El coche es muy rapido", 0 },
{ "The rain in Spain stays mainly in the plain", 9},
{ "XXXXX OOOOO TTTT", 0},
{ "Yes Si No No", 3},
{ "I have a cheerful live", 5},
{ "END", 0}
};
I could easily write 6 test cases and I would get the result I want. But this is not maintainable, since any further test added to the test cases would not be tested, it would require another test case to be written, which would be just boiler plate. Thus I've written a single test case which loops through all the test data like this :
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
class cppUnit_test: public CppUnit::TestFixture
{
private:
CPPUNIT_TEST_SUITE (cppUnit_test);
CPPUNIT_TEST(myTest);
CPPUNIT_TEST_SUITE_END();
public:
void myTest();
};
void cppUnit_test::myTest()
{
TestData* p = data;
while ( p->text != "END")
{
std::stringstream ss;
ss << "Text=\"" << p->text << "\" Counted=" <<
countEnglishWords(p->text) << " Expected=" << p->englishWords;
CPPUNIT_ASSERT_MESSAGE( ss.str().c_str(),
countEnglishWords(p->text) == p->englishWords );
++p;
}
}
int main()
{
CPPUNIT_TEST_SUITE_REGISTRATION (cppUnit_test);
CppUnit::Test *suite =
CppUnit::TestFactoryRegistry::getRegistry().makeTest();
CppUnit::TextUi::TestRunner runner;
runner.addTest(suite);
runner.run();
return 0;
}
The problem is that the previous code runs through the 1st test fine and also detects the error in the 2nd test but after that it stops testing. And the report is :
!!!FAILURES!!!
Test Results:
Run: 1 Failures: 1 Errors: 0
While the result I'd like to get is :
!!!FAILURES!!!
Test Results:
Run: 6 Failures: 4 Errors: 0
As I already mentioned in the comment cppunit 1.14.0 can support your use case.
I you want to reference an external array the quickest way is to use CPPUNIT_TEST_PARAMETERIZED. This macro expects two parameters: first similar to CPPUNIT_TEST a test method and then as a second parameter an iteratable.
Based on your code it would look like:
CPPUNIT_TEST_PARAMETERIZED(myTest, aData);
Now we need to adapt your myTest function a little bit.
void cppUnit_test::myTest(const TestData& data)
{
std::stringstream ss;
ss << "Text=\"" << data.text << "\" Counted=" <<
countEnglishWords(data.text) << " Expected=" << data.englishWords;
bool b = countEnglishWords(data.text) == data.englishWords;
std::string a = ss.str();
CPPUNIT_ASSERT_MESSAGE( a,
b);
}
Finally as the framework needs a way to report which test failed it expects that it can print the parameter that is passed to the test function. In this case the easiest way is to add a simple operator<< overload.
std::ostream& operator<<(std::ostream& strm, const TestData& data)
{
strm << data.text;
return strm;
}
If you combine these pieces you should quickly get a generic solution that will allow you to add as much data to your data array as you want without adapting the test code.
CPPUNIT_TEST_SUITE(TestSuite);
CPPUNIT_TEST_PARAMETERIZED(testMethod, {1, 2, 3, 4});
CPPUNIT_TEST_SUITE_END();
void testMethod(int /*val*/)
{
}

How to stop MsTest tests execution after *n* failed tests

I want to run unit tests via MS Test (from windows console) in a way that I can stop/kill the test execution whenever the failed tests count exceeds certain threshold value.
For my use case there is no point to keep running tests when certain percentage of the tests already failed.
I can only think in creating a new console app to wrap the mstest.exe execution, so I can parse the standard output in real-time,
and eventually kill the process, for example:
var pi = new ProcessStartInfo()
{
FileName = MS_TEST,
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = MS_TEST_ARGS
};
int passed = 0; int failed = 0;
using (var process = Process.Start(pi))
{
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
if (line.Contains("Passed"))
passed++;
if (line.Contains("Failed"))
failed++;
if (failed >= THRESHOLD)
{
process.Kill();
break;
}
}
}
Can anyone suggest a better way for doing this? I don't think this is natively supported by MsTest.
PowerShell seems to be an option, but the stdout redirect is not trivial.
Update
As a note, I cannot modify the test code, I need this to be done without modifying the tests code in any way.
Create a BaseTestClass which contains a method responsible for killing the process that runs the tests.
using System.Diagnostics;
namespace UnitTestProject1
{
public class BaseTestClass
{
private readonly int _threshold = 1;
private static int _failedTests;
protected void IncrementFailedTests()
{
if (++_failedTests >= _threshold)
Process.GetCurrentProcess().Kill();
}
}
}
Your must inherit all your test classes from BaseTestClass and use the [TestCleanup] attribute. The TestCleanup() method is evaluated when a test defined in the DemoTests class has finished running. Is in that method where we evaluate the output of the test that has just finished. If it failed, we kill the process responsible for running the tests.
In the following example we have defined three tests. The second test, Test_Substracting_Operation(), is intended to fail intentionally, so the third test will never be run.
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject1
{
[TestClass]
public class DemoTests : BaseTestClass
{
public TestContext TestContext { get; set; }
[TestCleanup]
public void TestCleanup()
{
if (TestContext.CurrentTestOutcome == UnitTestOutcome.Failed)
{
IncrementFailedTests();
}
}
[TestMethod]
public void Test_Adding_Operation()
{
// Arrange
int x = 1;
int y = 2;
// Act
int result = x + y;
// Assert
Assert.AreEqual(3, result);
}
[TestMethod]
public void Test_Substracting_Operation()
{
// Arrange
int x = 1;
int y = 2;
// Act
int result = x - y;
// Assert
Assert.AreEqual(100, result);
}
[TestMethod]
public void Test_Multiplication_Operation()
{
// Arrange
int x = 1;
int y = 2;
// Act
int result = x * y;
// Assert
Assert.AreEqual(2, result);
}
}
}

Google Tests ValuesIn with a global vector

I'm trying to run a bunch of google tests based off configuration files in a directory. This way I can just add a new file and run the tests without having to add it to my parametrized test and recompile. Here is my code:
typedef std::pair<QString, int> TestParam;
QString generatedLogic;
std::vector<TestParam> badExpressionTests;
class LogicBuilderTest : public ::testing::TestWithParam<TestParam> {};
GTEST_API_ int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
::generatedLogic = "/home/mitydsp/trunk/System/logicExecutionEngine/engine/include/GeneratedLogic.h";
QString dir = "/home/mitydsp/trunk/System/logicExecutionEngine/unittest/expressions/bad/";
QDirIterator it(dir, QStringList() << "*.txt", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
QString path = it.next();
QStringList nameParts = it.fileName().split("_");
int exitCode = nameParts[0].toInt();
::badExpressionTests.push_back(TestParam(path, exitCode));
}
std::cout << "Size of vector: " << badExpressionTests.size() << std::endl;
return RUN_ALL_TESTS();
}
/**
* Run parameterized test
*/
TEST_P(LogicBuilderTest, TestExitWithCode)
{
::testing::FLAGS_gtest_death_test_style = "threadsafe";
// Simulate fake main()
char arg0[] = "logicTest";
char* argv[] = { &arg0[0], NULL };
int argc = (int)(sizeof(argv) / sizeof(argv[0])) - 1;
EXPECT_EXIT({
// Need to run Qt Application because logic builder uses async QTimer::singleShot()
QCoreApplication app(argc, argv);
// Create a logic builder instance
LogicBuilder logicBuilder(
(int) ParameterStoreInterface::DEFAULT_PARAM_STORE_VALUES_KEY,
(int) ParameterStoreInterface::DEFAULT_PARAM_STORE_NAMES_KEY,
(int) ParameterStoreInterface::DEFAULT_PARAM_STORE_LOCK_KEY,
QString(GetParam().first),
QStringList(""),
QStringList(generatedLogic),
QString(LogicBuilder::DEFAULT_INTERMEDIATE_DIR),
QString(LogicBuilder::DEFAULT_OUTPUT_SRC),
QString(LogicBuilder::DEFAULT_OUTPUT_LIB),
true );
app.exec();
}, ::testing::ExitedWithCode(GetParam().second), "");
}
INSTANTIATE_TEST_CASE_P(TestBadExpressions, LogicBuilderTest,
::testing::ValuesIn(::badExpressionTests));
When I run this, it shows that 0 tests are being ran even though the vector says its size is two. How come these parametrized tests are not being ran?
Size of vector: 2
[==========] Running 0 tests from 0 test cases.
[==========] 0 tests from 0 test cases ran. (0 ms total)
[ PASSED ] 0 tests.
Originally I was running the tests by manually defining the configuration files but I don't like this:
INSTANTIATE_TEST_CASE_P(TestBadExpressions, LogicBuilderTest,
::testing::Values(
TestParam("unittest/expressions/bad/17_no_lhs.txt", LogicBuilder::LB_VARIABLE_NO_LHS),
TestParam("unittest/expressions/bad/25_incomplete_rhs.txt", LogicBuilder::LB_PARSE_ERROR)
));
I've spent the last hour trying to figure this out and then as soon as I post I come up with the solution. I'll leave this here because it may help someone in the future:
Instead of trying to create the list of files in main, pass the ValuesIn a function which loads the files and returns a vector.
std::vector<TestParam> GetFilesInDir()
{
std::vector<TestParam> values;
QString dir = "/home/mitydsp/trunk/System/logicExecutionEngine/unittest/expressions/bad/";
QDirIterator it(dir, QStringList() << "*.txt", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
QString path = it.next();
QStringList nameParts = it.fileName().split("_");
int exitCode = nameParts[0].toInt();
values.push_back(TestParam(path, exitCode));
}
return values;
}
INSTANTIATE_TEST_CASE_P(TestBadExpressions, LogicBuilderTest,
::testing::ValuesIn(GetFilesInDir()));
Thanks to Maksim Solovjov for reminding me that INSTANTIATE_TEST_CASE_P macro was being executed before main.
we spent some hours on this issue and thought this snippet will be helpful.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include "gtest/gtest.h"
GTEST_API_ main( int argc, char* argv[] ) {
testing::InitGoogleTest( &argc, argv );
return RUN_ALL_TESTS();
}
struct test_parms_s {
string name; // Simple name of this test
string description; // Description of this test
void* function_parms; // Pointer to test function specific data
};
std::vector<test_parms_s*> BuildTestData() {
test_parms_s* pTestDataA = new test_parms_s();
test_parms_s* pTestDataB = new test_parms_s();
test_parms_s* pTestDataC = new test_parms_s();
pTestDataA->name.assign("testA");
pTestDataA->description.assign("testA_desc");
pTestDataA->function_parms = NULL;
pTestDataB->name.assign("testB");
pTestDataB->description.assign("testB_desc");
pTestDataB->function_parms = NULL;
pTestDataC->name.assign("testC");
pTestDataC->description.assign("testC_desc");
pTestDataC->function_parms = NULL;
std::vector<test_parms_s*> values;
values.push_back(pTestDataA);
values.push_back(pTestDataB);
values.push_back(pTestDataC);
cout << "BuildTestData" << endl;
return values;
}
//------------------------------------------------------------------------
class Testy {
private:
string testname_;
public:
Testy( string testname );
~Testy();
string GetTestName();
void SetTestName( string testname );
};
Testy::Testy( string testname ) {
testname_.assign(testname);
}
Testy::~Testy() {}
string Testy::GetTestName() { return testname_; }
void Testy::SetTestName( string testname ) { testname_ = testname; }
//------------------------------------------------
class TestFixture : public ::testing::TestWithParam<test_parms_s*> {
protected:
Testy* testy;
virtual void SetUp() {
testy = new Testy( "Test");
}
virtual void TearDown() {
delete( testy );
}
};
//------------------------------------------------
TEST_P( TestFixture, ParamTest ) {
test_parms_s* pTestParms = GetParam();
cout << pTestParms->name << endl;
}
//------------------------------------------------
INSTANTIATE_TEST_CASE_P( TestFixture_instance, TestFixture,
::testing::ValuesIn(BuildTestData()));
//========================================================================
the output will be
BuildTestData
[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 3 tests from TestFixture_instance/TestFixture
[ RUN ] TestFixture_instance/TestFixture.ParamTest/0
testA
[ OK ] TestFixture_instance/TestFixture.ParamTest/0 (0 ms)
[ RUN ] TestFixture_instance/TestFixture.ParamTest/1
testB
[ OK ] TestFixture_instance/TestFixture.ParamTest/1 (0 ms)
[ RUN ] TestFixture_instance/TestFixture.ParamTest/2
testC
[ OK ] TestFixture_instance/TestFixture.ParamTest/2 (0 ms)
[----------] 3 tests from TestFixture_instance/TestFixture (0 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran. (0 ms total)
[ PASSED ] 3 tests.
I'm not an expert in manually instantiating Google Tests, but the way you did it can't possibly work: you call INSTANTIATE_TEST_CASE_P in the static context, so it is being evaluated before main is ever called.
You could try moving instantiation just before RUN_ALL_TESTS; however, I don't know what that macro does and this might be illegal. In that case, I think that you can't create your tests with INSTANTIATE_TEST_CASE_P in the dynamic way that you want.