我为自动测试编写了一个简单的C ++类(我尽可能简化了该问题)
class TestCase {
int passed, failed; // keeps the number of tests passed/failed so far.
public:
TestCase(): passed(0), failed(0) {}
void print() const {
int total = passed+failed;
int grade = (total==0? 0: 100*passed/total);
cout << "\n*** Right: " << passed << ". Wrong: " << failed << ". Grade: " << grade << " ***\n";
}
TestCase& check_equal(int actual, int expected) {
if (actual==expected) {
passed++;
} else {
failed++;
cout << "The result is " << actual << " but it should equal " << expected << "!" << endl;
}
return *this;
}
};
我这样使用:
TestCase testcase;
testcase
.check_equal(sum(1,2), 3)
.check_equal(factorial(5), 120)
...
.check_equal(fibonacci(4), 3)
.print();
只要检查的函数不引发异常,它就可以正常工作。如果“ check_equal”中的任何函数引发异常-不打印任何内容。我可以将整个块包装在try&catch中,例如:
TestCase testcase;
try {
testcase
.check_equal(sum(1,2), 3)
.check_equal(factorial(5), 120)
...
.check_equal(fibonacci(4), 3)
} catch (...) {
testcase.print();
}
但是,如果第一次检查成功并且第二次检查抛出异常,则等级为100,因为通过= 1,失败= 0,总计= 1。这显然是错误的。
我当然可以决定在出现异常的情况下,等级为0,但这也是错误的,因为某些检查确实成功了。 我希望成绩例如到目前为止的成功次数除以测试总数。但是,该类不知道测试的总数,因为该异常发生在查看所有测试之前!
一种可能的解决方案是将传递给check_equal的每个函数调用包装在try-catch块中,但是当有许多小型测试时,这变得非常麻烦。
修复此类的优雅解决方案是什么?
答案 0 :(得分:2)
您可以做的是推迟初始化actual
的函数调用以在函数内部进行。然后check_equal
可以处理该异常,如果确实发生异常,则将其取消(通过捕获),然后记录故障。有几种不同的处理方式,但一种方式是使用lambda之类的
template <typename Func>
TestCase& check_equal(Func actual, int expected) {
try {
auto act = actual();
if (act==expected) {
passed++;
} else {
failed++;
cout << "The result is " << act << " but it should equal " << expected << "!" << endl;
}
}
catch(...) {
failed++;
}
return *this;
}
您会这样称呼
TestCase testcase;
testcase
.check_equal([](){return sum(1,2);}, 3)
.check_equal([](){return factorial(5);}, 120)
...
.check_equal([](){return fibonacci(4);}, 3)
.print();
您甚至可以使用宏删除样板
#define FUNCTOR(func) [](){return func;}
TestCase testcase;
testcase
.check_equal(FUNCTOR(sum(1,2)), 3)
.check_equal(FUNCTOR(factorial(5)), 120)
...
.check_equal(FUNCTOR(fibonacci(4)), 3)
.print();