Главная страница
Навигация по странице:

  • Написание модульного теста

  • Раздатка Модульное тестирование кода на C легкое. Настройка проекта


    Скачать 48.4 Kb.
    НазваниеНастройка проекта
    Дата06.03.2023
    Размер48.4 Kb.
    Формат файлаdocx
    Имя файлаРаздатка Модульное тестирование кода на C легкое.docx
    ТипДокументы
    #972414

    Модульное тестирование кода на C++ с помощью Qt Test

    Настройка проекта


    Идея Qt Test заключается в том, что каждый тестовый случай должен быть независимым исполняемым файлом и иметь собственный проект.

    Самый быстрый способ создать проект – использовать шаблон «Проект автотестирования» (Auto Test Project), который находится в группе «Другой проект» (Other Project) диалогового окна «Новый проект» (New Project).



    Рисунок 1 – Создание проекта автоматического тестирования в Qt Creator для модульного тестирования кода на C++ с помощью Qt Test

    Мастер проведет вас через настройку проекта. В частности, в разделе «Подробнее» (Details) можно указать несколько параметров.



    Рисунок 2 – Детали настройки проекта автотестирования в Qt Creator

    «Имя теста» (Test case name) будет именем класса, представляющего юнит-тест.

    Если вы не хотите использовать мастер проекта, вам нужно добавить testlib в переменную QT в qmake файле проекта:

    QT += testlib

    Если в вашем модульном тесте нет элементов графического интерфейса, можно отключить модуль gui:

    QT -= gui

    Написание модульного теста

    Чтобы написать модульный тест кода на C++ с Qt, вам необходимо создать класс, который наследуется от QObject и реализует, по крайней мере, один частный слот. Каждый частный слот – это независимый тест.

    Самый простой класс модульного теста выглядит примерно так:

    #include
    class TestMinimal : public QObject

    {

    Q_OBJECT
    private slots:

    void testFoo();

    };

    Вы также можете реализовать 4 специальных частных слота, которые используются для операций инициализации и очистки:

    // вызывается перед первой тестовой функцией

    void initTestCase();

    // вызывается перед каждой тестовой функцией

    void init();

    // вызывается после каждой тестовой функции

    void cleanup();

    // вызывается после последней тестовой функции

    void cleanupTestCase();

    Кроме того, у вас в тестовом классе могут быть и другие члены данных и функции, поскольку это обычный класс C++.

    Пример класса модульного теста


    Класс модульного теста:

    #include "Calculator.h"
    #include
    class TestCalculator: public QObject

    {

    Q_OBJECT
    private slots:

    // -- настройка/очистка --

    void init();
    // -- тесты --

    void testConstructor();

    void testSum();
    private:

    const int A0 = 0;

    const int B0 = 0;
    private:

    Calculator mCalc;

    };

    Функции класса TestCalculator будут объяснены в следующих разделах.

    Проверка значений


    Для проверки того, что во время теста всё работает так, как ожидалось, Qt Test предоставляет различные макросы.

    Самая простая проверка, которую вы можете выполнить, – это проверить, истинно ли утверждение. Для этого вы можете использовать макрос QVERIFY:

    void TestCalculator::testConstructor()

    {

    // значения по умолчанию

    Calculator c1;
    QVERIFY(c1.getA() == 0);

    QVERIFY(c1.getB() == 0);

    В этом коде всё хорошо, пока функции getA() и getB() возвращают 0. Если это так, при запуске теста вы увидите следующее сообщение:

    PASS : TestCalculator::testConstructor()

    В случае сбоя сообщение уведомит вас о том, что что-то пошло не так:

    FAIL! : TestCalculator::testConstructor() 'c1.getA() == 0' returned FALSE. ()

    Loc: [../QtTestIntroduction/TestCalculator.cpp(16)]

    Сообщение об ошибке не содержит подробной информации о том, что пошло не так. Оно только говорит вам, какое выражение было ложным.

    Если вам нужно добавить к проверке немного контекста, вы можете использовать вторую версию макроса, QVERIFY2, который позволяет добавить сообщение об ошибке:

    // полный конструктор

    const int A = 10;

    const int B = 2;

    Calculator c2(A, B);
    QVERIFY2(c2.getA() == A, "first operand doesn't match"); // не совпадает первый операнд

    QVERIFY2(c2.getB() == B, "second operand doesn't match"); // не совпадает второй операнд

    }

    В случае сбоя сообщение отладки добавит дополнительную информацию, переданную в макрос:

    FAIL! : TestCalculator::testConstructor() 'c2.getB() == B' returned FALSE. (second operand doesn't match)

    Loc: [../QtTestIntroduction/TestCalculator.cpp(25)]

    Добавление сообщения об ошибке может показаться лишней работой, но оно поможет людям, не знакомым с вашим кодом. Вы всегда должны предпочесть использование QVERIFY2 (вместо QVERIFY), чтобы включать в ваши тесты дополнительную информацию.

    Qt Test также предоставляет другие версии QVERIFY, которые предоставляют некоторые дополнительные функции. Например, QTRY_VERIFY_WITH_TIMEOUT или QVERIFY_EXCEPTION_THROWN. Первый вариант позволяет проверять условие несколько раз, прежде чем посчитать его ложным. Последний проверяет, выброшено ли конкретное исключение. Для получения дополнительной информации обратитесь к справочной информации в конце данного руководства.

    Сравнение значений


    Если вам нужна дополнительная информация, когда тест не проходит, и если вы хотите сравнить какое-либо значение, вам понадобится макрос QCOMPARE:

    void TestCalculator::testSum()

    {

    // sum default

    QCOMPARE(mCalc.Sum(), A0 + B0);

    Этот макрос будет сравнивать 2 параметра с использованием наиболее подходящего оператора тестирования. Например, для сравнения чисел с плавающей запятой используется функция Qt qFuzzyCompare().

    Когда QCOMPARE выдает сбой, он предоставляет более подробную информацию:

    FAIL! : TestCalculator::testSum() Compared values are not the same

    Actual (mCalc.Sum()): 10

    Expected (A0 + B0) : 12

    Loc: [../QtTestIntroduction/TestCalculator.cpp(39)]

    В этом случае вы также узнаете, каковы возвращаемые и ожидаемые значения. Что во многих случаях очень полезно.

    Также QCOMPARE имеет разные версии, предлагающие дополнительные функции, например QTRY_COMPARE_WITH_TIMEOUT, который проверяет условие несколько раз, прежде чем считать его ложным. Для получения дополнительной информации обратитесь к справочной информации в конце статьи.

    Функция main приложения


    Как упоминалось ранее, каждый юнит-тест должен быть независимым исполняемым файлом. Это означает, что после создания юнит-теста вам понадобится функция main для его запуска.

    Для формирования кода функции main, в соответствии с вашими потребностями, Qt Test предоставляет 3 макроса:

    // полное приложение Qt

    QTEST_MAIN(TestName)
    // приложение Qt только с core: без GUI, но есть обработка событий

    QTEST_GUILESS_MAIN(TestName)
    // нет приложения Qt: без GUI и обработки событий

    QTEST_APPLESS_MAIN(TestName)

    Вы можете добавить один из этих макросов в конец файла cpp, определяющего юнит-тест. В этом примере, поскольку я тестировал простой код на C++ (без Qt), я использовал:

    QTEST_APPLESS_MAIN(TestCalculator)

    Следует помнить, что если вы объявляете класс юнит-теста непосредственно в файле .cpp (а не в файле .h), вам нужно будет добавить в конце дополнительный #include:

    QTEST_APPLESS_MAIN(TestCalculator)

    #include "TestCalculator.moc"

    Это требует Qt для правильной работы.

    Полный исходный текст программы:

    calculator.h

    #ifndef CALCULATOR_H

    #define CALCULATOR_H

    #pragma once

    // example class to test

    class Calculator

    {

    public:

    Calculator(int a = 0, int b = 0) : mA(a), mB(b) { }

    int GetA() const { return mA; }

    void SetA(int a) { mA = a; }

    int GetB() const { return mB; }

    void SetB(int b) { mB = b; }

    int Sum() const { return mA + mB; }

    int Diff() const { return mA - mB; }

    int Mult() const { return mA * mB; }

    int Div() const { return mA / mB; }

    private:

    int mA;

    int mB;

    };

    #endif // CALCULATOR_H

    qt_test_introduction.pro
    QT += testlib

    QT -= gui

    CONFIG += qt console warn_on depend_includepath testcase

    CONFIG -= app_bundle

    TEMPLATE = app

    SOURCES += tst_testcalculator.cpp

    HEADERS += \

    calculator.h \

    tst_testcalculator.h
    tst_testcalculator.cpp
    #include "tst_testcalculator.h"

    // -- setup/cleanup --

    void TestCalculator::init()

    {

    mCalc.SetA(A0);

    mCalc.SetB(B0);

    }

    // -- tests --

    void TestCalculator::testConstructor()

    {

    // default values

    Calculator c1;

    QVERIFY(c1.GetA() == 0);

    QVERIFY(c1.GetB() == 0);

    // full constructor

    const int A = 10;

    const int B = 2;

    Calculator c2(A, B);

    QVERIFY2(c2.GetA() == A, "first operand doesn't match");

    QVERIFY2(c2.GetB() == B, "second operand doesn't match");

    }

    void TestCalculator::testSum()

    {

    // sum default

    QCOMPARE(mCalc.Sum(), A0 + B0);

    // sum after setting a and b

    const int A = 10;

    const int B = 2;

    mCalc.SetA(A);

    mCalc.SetB(B);

    QCOMPARE(mCalc.Sum(), A + B);

    }

    // generate basic main: no GUI, no events

    QTEST_APPLESS_MAIN(TestCalculator)

    // uncomment next line if class declaration is in .cpp (no .h)

    //#include "TestCalculator.moc"

    tst_testcalculator.h
    #ifndef TST_TESTCALCULATOR_H

    #define TST_TESTCALCULATOR_H

    #include "calculator.h"

    #include

    class TestCalculator: public QObject

    {

    Q_OBJECT

    private slots:

    // -- setup/cleanup --

    void init();

    // -- tests --

    void testConstructor();

    void testSum();

    private:

    const int A0 = 0;

    const int B0 = 0;

    private:

    Calculator mCalc;

    };

    #endif // TST_TESTCALCULATOR_H


    написать администратору сайта