Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在编译过程中实现功能单元测试?_C++_Unit Testing_Compilation - Fatal编程技术网

C++ 如何在编译过程中实现功能单元测试?

C++ 如何在编译过程中实现功能单元测试?,c++,unit-testing,compilation,C++,Unit Testing,Compilation,我正在写一个函数,它将一个复杂的公式应用于一组整数。当我做很多更改时,我总是先编译,然后在运行时做一些测试用例,以确保我没有破坏任何东西,所以我想“好吧,我将在代码中放一些测试用例” 但这当然是不可取的,因为函数需要一段时间来完成它的工作,并且每次我执行程序时都会运行测试。有没有简单的方法来自动执行此操作,以便在编译时检查某些情况?下面是一个小示例,它显示了我当前(不太理想)的方法 #包括 int-binom(int,int); int main(){ //我不希望这些测试发生在运行时。。。 b

我正在写一个函数,它将一个复杂的公式应用于一组整数。当我做很多更改时,我总是先编译,然后在运行时做一些测试用例,以确保我没有破坏任何东西,所以我想“好吧,我将在代码中放一些测试用例”

但这当然是不可取的,因为函数需要一段时间来完成它的工作,并且每次我执行程序时都会运行测试。有没有简单的方法来自动执行此操作,以便在编译时检查某些情况?下面是一个小示例,它显示了我当前(不太理想)的方法

#包括
int-binom(int,int);
int main(){
//我不希望这些测试发生在运行时。。。
bool test1=(binom(5,2)!=10);//5选择2应该是10
bool test2=(binom(7,4)!=35);//7选择4应该是35
如果(测试1 | |测试2){
标准::cout n;
std::cout>k;

std::cout人们通常会将他们的测试用例从他们的主程序中分离出来。但是,在
main
文件中声明和定义函数会很困难。最理想的情况是,这些函数/类型将在它们自己的头文件中声明,并在它们自己的实现文件中定义

然后,您可以编写第二个程序,该程序使用相同的头并执行测试

// binomial.h
#ifndef BINOMIAL_H
#define BINOMIAL_H

int binom(int, int);

#endif

// binomial.cpp

#include "binomial.h"

int binom(int n, int k) {
  if (k > n/2)
    k = n-k;
  int nCk = 1, i=1;
  for ( ; i<=k; ++i) {
    nCk *= n-k+i;
    nCk /= i;
  }
  return nCk;
}

现在,您每次构建时都会运行该测试,并且您知道您的功能没有被破坏(好吧,这些测试可能更全面,但您已经明白了)。也有专门用于单元测试的库,可以使您的生活更轻松。

通常会将其测试用例从主程序中分离出来。但是,在您的
main
文件中声明和定义函数将非常困难。最理想的情况是,这些函数/类型将在它们自己的头中声明并在其自己的实现文件中定义

然后,您可以编写第二个程序,该程序使用相同的头并执行测试

// binomial.h
#ifndef BINOMIAL_H
#define BINOMIAL_H

int binom(int, int);

#endif

// binomial.cpp

#include "binomial.h"

int binom(int n, int k) {
  if (k > n/2)
    k = n-k;
  int nCk = 1, i=1;
  for ( ; i<=k; ++i) {
    nCk *= n-k+i;
    nCk /= i;
  }
  return nCk;
}

现在,您每次构建时都会运行该测试,并且您知道您的功能没有被破坏(好吧,这些测试可能更全面,但您已经明白了)。也有专门用于单元测试的库,可以使您的生活更轻松。

您可以使用
constepr
在编译时评估
binom
,并使用
static\u assert
对其进行测试。请注意,您还需要用尾部递归来表示迭代。在
binom
示例中,这是直截了当:

#include <iostream>

constexpr int binom_loop(int n, int k, int i, int nCk) {
  return i <= k
    ? binom_loop(n, k, i + 1, nCk * (n-k+i) / i)
    : nCk;
}

constexpr int binom(int n, int k) {
  return binom_loop(n, k > n/2 ? n-k : k, 1, 1);
}

// assert that the calculation works - at compile-time
static_assert (binom(5, 2) == 10,
               "5 choose 2 should be 10");

int main() {
  // enum demonstrates that binom() can be evaluated at compile-time
  // if called with literal args
  enum {
    X = binom(5, 2),
  };
  std::cout << int(X) << '\n';   // prints 10
}
#包括
constexpr int binom_循环(int n,int k,int i,int nCk){
返回i n/2?n-k:k,1,1);
}
//断言计算在编译时有效
静态断言(binom(5,2)==10,
“5选择2应为10”);
int main(){
//enum演示了可以在编译时计算binom()
//如果使用文字参数调用
枚举{
X=binom(5,2),
};

std::cout您可以使用
constexpr
在编译时评估
binom
,并使用
static\u assert
对其进行测试。请注意,您还需要用尾部递归来表示迭代。在
binom
示例中,这很简单:

#include <iostream>

constexpr int binom_loop(int n, int k, int i, int nCk) {
  return i <= k
    ? binom_loop(n, k, i + 1, nCk * (n-k+i) / i)
    : nCk;
}

constexpr int binom(int n, int k) {
  return binom_loop(n, k > n/2 ? n-k : k, 1, 1);
}

// assert that the calculation works - at compile-time
static_assert (binom(5, 2) == 10,
               "5 choose 2 should be 10");

int main() {
  // enum demonstrates that binom() can be evaluated at compile-time
  // if called with literal args
  enum {
    X = binom(5, 2),
  };
  std::cout << int(X) << '\n';   // prints 10
}
#包括
constexpr int binom_循环(int n,int k,int i,int nCk){
返回i n/2?n-k:k,1,1);
}
//断言计算在编译时有效
静态断言(binom(5,2)==10,
“5选择2应为10”);
int main(){
//enum演示了可以在编译时计算binom()
//如果使用文字参数调用
枚举{
X=binom(5,2),
};

std::cout一般来说,我建议您将编译和运行单独的单元测试(在本例中,单元是一个函数)作为发布程序的两个强制性步骤

从应用程序启动时运行测试的现状开始。除非您特别希望程序每次运行时都进行自检,否则您希望将测试与程序的运行分开。您可以在编译代码时执行生成后步骤,每次都运行测试。如果测试通过,它将将已测试(有时称为已升级)的可执行文件发布到输出文件夹。这样,您就可以始终知道已发布的可执行文件经过了良好的测试

您希望在每次启动应用程序时运行测试的情况是,程序是否需要测试操作环境的某些方面,例如,确保正确的第三方资源/实例/服务可用并受支持。即使如此,最好在您的build-t中尽可能多地进行测试首先进行ime测试,以避免程序上线时出现意外情况

关于“编译时函数执行”,它更像是一种为已知参数的函数的某些输出设置常量值的方法。尽管如此,有一些新的c++11功能(如果您的编译器支持),允许您在运行时检查常量表达式(如static_assert)请参见答案中的一个例子。就我个人而言,我对在测试中使用此选项有所保留,因为我会觉得测试和代码过于耦合,并且我违反了“关注点分离”的原则。具体来说:-

  • 我会担心过多的编译时间
  • 有时,即使其中一个测试失败,我也可能想运行我的程序。对测试进行注释可能会使我忘记不将它们放回
  • 这只适用于遵守相当严格的约束条件的特定功能,因此仅适用于某些类型的测试方法
  • 我可能希望在不重新编译或注释测试的情况下运行测试的子集
  • 我可能希望在完全相同的可执行文件上运行一组不同的测试,而不冒通过重新编译引入更改的风险
这些都是类似的理由