本主题说明 C++test 如何对模板功能执行编码标准分析和单元测试。

在本章节中:

从 C++ 模板收集代码覆盖率

C++test 可以收集 C++ 模板的代码覆盖率信息。为所有模板实例收集和报告代码覆盖率信息。要启用从 C++ 模板收集代码覆盖率:

  1. 请打开测试配置,然后选择 执行>生成 选项卡
  2. 在【执行详情】部分中,单击【检测模式】字段中的 编辑
  3. 启用了测试配置执行选项卡的【检测功能】面板里【高级选项】部分的 Enable coverage for C++ templates 选项。

了解 C++test 的实例支持

C++test 可以对实例化的函数模板和实例化的类模板成员执行静态分析和单元测试。在这种情况下,“实例化”是指:

C++test 可以:

  • 对实例主体执行静态分析。
  • 自动为实例生成测试用例。

实例的主体检测是有限的。因此,没有来自实例的存根调用,并且在报告异常时可能存在不准确的堆栈跟踪(这些限制不适用于显式模板专门化)。

使用 "#pragma instantiate" 来强制模板实例化

如果在测试的源代码中没有使用给定的模板实例,您可以通过在测试的代码中插入 #pragma instantiate 来强制模板实例化,例如:

#pragma instantiate atype<int>

C++ 前端内部文档中, Edison Design Group, Inc. 解释道:

实例化 pragma 的参数可以是:

  • 模板类名称 A<int>
  • 模板类声明类 A<int>
  • 成员函数名称 A<int>::f
  • 静态数据成员名称 A<int>::i
  • 静态数据声明 int A<int>::i
  • 成员函数声明 void A<int>::f(int, char)
  • 模板函数声明 char* f(int, float)

其中参数是模板类名称(例如,A<int> 或 class A<int>)的编译指示等效于对该类中声明的每个成员函数和静态数据成员重复该编译指示。当实例化整个类时,可以使用 do_not_instantiate 编译指示排除给定的成员函数或静态数据成员。例如:

#pragma instantiate A<int>
#pragma do_not_instantiate A<int>::f

要实例化,模板实体的模板定义必须出现在编译中。如果使用实例化实用程序显式请求了实例化,并且没有模板定义可用或未提供特定定义,则会发出错误。


template <class T> void f1(T); // No body provided  
template <class T> void g1(T); // No body provided
void f1(int) {} // Specific definition
void main()  {
  int i;
  double d; 
   f1(i);
   f1(d);
   g1(i);
   g1(d); 
}
#pragma instantiate void f1(int) // error - specific definition  
#pragma instantiate void g1(int) // error - no body provided


f1(double) 和 g1(double) 将不会被实例化(因为没有提供任何主体),但是在编译过程中不会产生任何错误(如果在链接时没有提供任何主体,则会产生链接器错误)。

成员函数名称(例如,A<int>::f)仅在引用单个用户定义的成员函数(即,不是重载函数)时才可用作编译指示参数。不考虑编译器生成的函数,因此即使存在由编译器生成的同名副本构造函数,名称也可以引用用户定义的构造函数。可以通过提供完整的成员函数声明来实例化重载的成员函数,如 #pragma instantiate char* A<int>::f(int, char*)中所述

实例编译指示的参数可能不是编译器生成的函数、内联函数或纯虚函数。”

潜在的局限性

  • "#pragma instantiate" (内联函数、纯虚函数等)有一定的局限性;有关详情,请查阅 使用 "#pragma instantiate" 来强制模板实例化 。
  • C++test 不能为没有实例化构造函数、析构函数的模板类自动生成测试用例;相反,可以使用 #pragma instantiate 来实例化构造函数、析构函数,或者在测试的代码中创建给定类的实例(作为全局变量等等)。

温馨提示

如果您没有任何可进行模板实例化的源代码,则可以使用


#ifdef PARASOFT_CPPTEST 
#pragma instantiate ... 
...
#endif


或者,您可以使用

#ifdef PARASOFT_CPPTEST
#include "pragma_instantiate.h" 
#endif

其中包含的头包含具有必要类型的实例化。

第二个选项的好处是,如果向类型集添加内容,如果没有定义 PARASOFT CPPTEST (没有时间戳更改),就不会更改头文件,并且可以节省重新编译的时间。

这样,编译指示就不会干扰您的常规代码。通常,这应该在声明模板的头文件中完成。对于某些编译器,模板只能位于标头中,而它们没有源文件。


  • No labels