目前,IMO,谷歌类型参数化测试很烦人。你必须这样做:
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);
这些东西似乎可以自动化。例如:
#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);
(这些宏可以很容易地扩展到非常大的尺寸,然后它们就足以满足大多数用途)
然而,这种方法很有效,所以我想让它看起来更正常,因此它更具可读性。这需要采取这样的方式:
#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
我不确定是否可以做到。这可能吗?
我只想发布最后一段代码,但其他人似乎认为想象一个用例太晦涩,所以我也想提供它。
答案 0 :(得分:1)
我使用gtest和celero遇到了你的问题。 我使用宏和python脚本的组合来自动化大部分锅炉板代码。
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(); \
};
我像这样使用它
`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
最后你可以看到python脚本的位置。它解析注释中的信息并通过迭代生成所有TEST_F(****)代码,尽管所有可能的键组合并将其放入包含文件中。 python脚本还克服了c ++中宏和模板的问题,即如果你有的话 TEST_F(例如,TEST_NAME){test_code();}; 预处理器会认为TEST_F中有三个参数 所以你需要这样写 typedef example class_type_1_type_2; TEST_F(class_type_1_type_2,test_name){test_code();}; (告诉python脚本将某些内容拉入类型def,只需将类型放在两个$之间,如上例所示) 你调用python脚本就好 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()
对不起,如果长篇文章很烦人,但我花了很多时间试图加快编写单元测试和基准测试,我希望这些东西也可以帮到你, 警告:python脚本可能是世界上写得最好的,但是可以满足我的需求。 如果你有关于如何使用它的任何请求,请随时向我询问,或者如果你需要它做某事我不能做,我可以添加它。我正在努力建立github。