在数组中的函数上使用宏使gtest类型参数化测试更简洁
Using macros on functions in an array to make gtest typed-parameterized tests more succinct
现在,在我看来,Google类型参数化测试很烦人。你必须这样做:
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
我不确定是否有可能做到。这可能吗?
我将简单地发布最后一点代码,但其他人似乎认为它太模糊了,无法想象一个用例,所以我也想提供它。
我使用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(****)代码,并将其放入include文件中。python脚本还克服了c++中宏和模板的问题,即,如果您有TEST_F(例如,test_name) {test_code ();};预处理器会认为TEST_F中有三个参数所以你需要这样写typepedef example class_type_1_type_2;TEST_F (class_type_1_type_2 test_name) {test_code ();};(要告诉python脚本将某些内容拉入类型def中,只需将类型放在两个$之间,就像上面的例子一样)可以这样调用python脚本cover .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。 相关文章:
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- "std::shared_ptr":不是参数"_Ty"的有效模板类型参数
- 具有可变参数非类型参数的模板专用化
- 函数类型参数的模板参数推导
- PowerShell 使用结构类型参数调用 C++ DLL 的导出函数
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 为模板传递非类型参数 agument
- 为什么带有类型参数的运算符 () 可以应用于 result_of 上下文中的类型?
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 如何避免具有相同类型参数的函数中的错误
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- c++非类型参数包扩展
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 在不同的模板参数包之间分发非类型参数包
- 如何在使用容器和字符串时强制使用显式分配器类型参数
- 错误:一元"*"的类型参数无效(具有"int"):使用 mergesort 计算
- 按类型参数进行GTEST滤波器测试
- 在数组中的函数上使用宏使gtest类型参数化测试更简洁
- gtest类型参数化的多态性