问题
Right now, IMO, Google typed-parameterized tests are annoying. You have to do:
template <typename fixtureType>
class testFixtureOld : public ::testing::Test
{
};
// Tell google test that we want to test this fixture
TYPED_TEST_CASE_P(testFixtureOld);
// Create the tests using this fixture
TYPED_TEST_P(testFixtureOld, OIS1Old)
{
TypeParam n = 0;
EXPECT_EQ(n, 0);
}
TYPED_TEST_P(testFixtureOld, OIS2Old)
{
TypeParam n = 0;
EXPECT_EQ(n, 0);
}
// Register the tests we just made
REGISTER_TYPED_TEST_CASE_P(testFixtureOld, OIS1Old, OIS2Old);
// Run the tests
typedef ::testing::Types<char, int, unsigned int> TypesTestingOld;
INSTANTIATE_TYPED_TEST_CASE_P(RunOldTests, testFixtureOld, TypesTestingOld);
Much of this stuff seems it could be automated. For example:
#define TYPED_TESTS_P(fixture, testName1, test1, testName2, test2) TYPED_TEST_CASE_P(fixture); TYPED_TEST_P(fixture, testName1) test1 TYPED_TEST_P(fixture, testName2) test2 REGISTER_TYPED_TEST_CASE_P(fixture, testName1, testName2);
#define RUN_TYPED_TESTS_P(testSuiteName, fixture, type1, type2, type3) typedef::testing::Types<type1, type2, type3> TypesTesting; INSTANTIATE_TYPED_TEST_CASE_P(testSuiteName, fixture, TypesTesting);
template <typename fixtureType>
class testFixtureNew : public ::testing::Test
{
};
// Make our tests. This tells google test that we want to test this fixture,
// creates the tests using this fixture, and registers them.
TYPED_TESTS_P(testFixtureNew,
OISNew,
{
TypeParam n = 0;
EXPECT_EQ(n, 0);
},
OIS2New,
{
TypeParam n = 0;
EXPECT_EQ(n, 0);
}
)
// Run the tests
RUN_TYPED_TESTS_P(RunNewTests, testFixtureNew, char, int, unsigned int);
(where those macros could be easily expanded to a very large size and then they will be sufficient for most use)
This works, however, this syntax is rather abnormal, so I'd like to make it more normal looking so it is more readable. This requires a way of doing something like this:
#include <std>
using namespace std;
#define PassIntoThenListOut(inArg, fun1, fun2) something
PassIntoThenListOut(6,
int a(int foo)
{
cout << "5+first = " << (5+foo);
},
int b(int bar)
{
cout << "10+second = " << (10+bar);
}
)
// Should output:
// 5+first = 11
// 10+second = 16
// ArgumentNames: foo bar
which I'm not sure is possible to do. Is this possible?
I would simply post the last bit of code but others seem to think that it is too obscure to imagine a use case so I wanted to provide that as well.
回答1:
I have run into your problem using gtest and celero. I use a combination of macros and a python script to automate much of the boiler plate code.
here are the macros i use
#define DEFINE(name,threads) \
void name(); \
REGISTER(name,threads) \
#define REGISTER(name,threads) \
SINGLE(name) \
THREADED(name,threads) \
#define THREADED(name, num_of_threads) \
void name##Threaded(){ \
std::vector< std::thread > threads; \
for(int i=0; i<num_of_threads; i++){ \
threads.push_back( std::thread([this](){this->name##Single();})); \
}; \
for(auto &t : threads){ \
t.join(); \
}; \
};
#define SINGLE(name) \
void name##Single(){ \
this->name(); \
};
and i use it like this
`template<typename T>
class LocationTest : public ::testing::Test{
protected:
location<T> policy;
DEFINE(mallocfreetest, LOCATION_THREADS)
DEFINE(copytest, LOCATION_THREADS)
};'
template<typename T>
void LocationTest<T>::mallocfreetest(){
void* p=NULL;
p=policy.New(10);
policy.Delete(p);
EXPECT_TRUE(p);
};
template<typename T>
void LocationTest<T>::copytest(){
int a=1;
int* a_ptr=&a;
int b=0;
int* b_ptr=&b;
policy.MemCopy(a_ptr,b_ptr,sizeof(int));
EXPECT_EQ(1,b);
};
template<>
void LocationTest<device>::copytest(){
size_t size=sizeof(int);
int a=1;
int* a_d=static_cast<int*>( policy.New(size) );
ASSERT_TRUE(a_d);
int b=0;
int* b_d=static_cast<int*>( policy.New(size) );
ASSERT_TRUE(b_d);
cudaMemcpy(a_d,&a,size,cudaMemcpyHostToDevice);
cudaMemcpy(b_d,&b,size,cudaMemcpyHostToDevice);
policy.MemCopy(a_d,b_d,size);
cudaMemcpy(&b,b_d,size,cudaMemcpyDeviceToHost);
EXPECT_EQ(1,b);
};
#define HOST host
#define UNIFIED unified
#define DEVICE device
#define PINNED pinned
//python:key:policy=HOST UNIFIED DEVICE PINNED
//python:key:tests=copytestSingle mallocfreetestSingle copytestThreaded mallocfreetestThreaded
//python:template=TEST_F($LocationTest<|policy|>$,|tests|){this->|tests|();}
//python:start
//python:include=location.test
#include"location.test"
//python:end
#undef HOST
#undef UNIFIED
#undef DEVICE
#undef PINNED
#undef LOCATION_THREADS
at the end you can see where the python script comes in. it parses the information in the comments and generates all the TEST_F(****) code by iteration though all possible cominations of keys and putting it into the include file. the python script also overcomes the issues with macros and templates in c++, namely, if you have TEST_F(example,test_name){test_code();}; the preprocessor will think there are three paramaters in TEST_F so you need to write it like this typedef example class_type_1_type_2; TEST_F(class_type_1_type_2, test_name){test_code();}; (in to tell the python script to pull something into a type def just put the type between two $ like in the example above) you call the python script like coverage.py -i test_file.cpp
import os
import re
import copy
import getopt
import sys
#find functions,types,locations list;
def getoutputfile():
global contents
functionRegex=re.compile(r"//python:include=(.*)")
fun=functionRegex.findall(contents)
return fun[0]
def getkey():
global contents
params={}
functionRegex=re.compile(r"//python:key:(\w*)=(.*)")
fun=functionRegex.findall(contents)
for i in range( len(fun) ):
params[ fun[i][0] ]=fun[i][1].split(" ")
return params
def get_template():
global contents
functionRegex=re.compile(r"//python:template=(.*)")
fun=functionRegex.findall(contents)
return fun
def getnumlines(array,temp):
num=1
for i in array:
num*=i
return num*len(temp)
def initializeMaxArray(array):
global keys
global paramaters
for i in range(keys):
j=paramaters.keys()[i]
array[i]=len( paramaters[j])
def increment(a,k):
if k<keys:
a[k]+=1
if a[k]>=max_array[k]:
a[k]=0
a=increment(a,k+1)
# *******************read in file and data
a,b=getopt.getopt(sys.argv[1:],"i:")
input_file=a[0][1]
source_file=open(input_file,"r")
contents=source_file.read()
source_file.close()
#*****************initalize varaibles
paramaters=getkey()
template=get_template()
keys=len( paramaters.keys() )
max_array=[0]*keys
initializeMaxArray(max_array)
lines=getnumlines(max_array,template)
contents_new=[]
for i in range(len(template)):
contents_new+=[template[i]]*(lines/len(template))
for i in range(len(contents_new)):
contents_new[i]+='\n'
temps=len(template)
array=[[0]*keys]*(lines*temps)
for i in range(lines-1):
array[i+1]=copy.copy(array[i])
increment(array[i+1],0)
#variable replacement
for j in range(lines):
for i in range(keys):
key=paramaters.keys()[i]
x=array[j][i]
result=contents_new[j].replace("|"+key+"|",paramaters[key][x])
contents_new[j]=result
#typedef insertion
typedef_list=[];
typedefreg=re.compile(r".*\$(.+)\$.*")
for k in range(len( contents_new) ):
matches=typedefreg.findall(contents_new[k] )
for j in matches:
match=j
clear={"<":"_",">":"_",",":"_"," ":""}
for i in clear.keys():
match= match.replace(i,clear[i] )
for j in matches:
typedef=r"typedef "+j+" "+match+"; \n" rep="$"+j+"$"
contents_new[k]=contents_new[k].replace(rep,match)
typedef_list.append(typedef)
contents_new.insert(0,"//Tests/benchmarks \n")
typedef_list.insert(0,"//typedefs \n")
output=typedef_list+contents_new
outputfile=getoutputfile()
#write out to file
destination_file=open(outputfile,'w')
destination_file.write( "".join(output) )
destination_file.close()
im sorry if the long post is annoying but i spent allot of time trying to speed up writing unit test and benchmarks and i hope these things can help you as well, WARNING: the python script is probably note the best written in the world but works for what i need it for. if you have anyquest about how to use this come feel free to ask me more or if you need it to do something it doesnt do i could add it to it. im working on putting up on github.
来源:https://stackoverflow.com/questions/32082262/using-macros-on-functions-in-an-array-to-make-gtest-typed-parameterized-tests-mo