Класс тестового случая, который правильно обрабатывает исключения - PullRequest
0 голосов
/ 18 февраля 2019

Я написал простой класс 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, но это становится очень громоздким, когда есть много маленьких тестов.

Что такое элегантное решение для исправления этого класса?

1 Ответ

0 голосов
/ 18 февраля 2019

Что вы можете сделать, так это отложить вызов функции, инициализированный actual, внутри функции.Затем check_equal может обработать исключение и, если оно возникнет, отменить его (перехватив) и затем записать сбой.Есть несколько разных способов справиться с тем, как это сделать, но один способ - использовать лямбду, например

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...