html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Юнит-тестирование в Qt tutorial


gollum подметил что в тексте картинки есть ошибка

Салют, хабр! Как дела?

Хотел немного подучится чему-то. Искал на хабре в хабе «Qt Software» хоть какой-то пост про юнит-тестирование в Qt. Не нашел. Тут я расскажу базовые вещи про юнит-тестирование на Qt (не ожидайте могучего шаманства). На самом деле, юнит-тестить в Qt довольно просто. Что бы узнать как это делать, приглашаю читать дальше.

Я постараюсь разбить все на части. Погрупирую, так сказать. Начнем.

Теория


Если вы знаете теорию юнит-тестирования — можете пропустить этот пункт.

У нас есть код. Как бы мы этого не хотели в нем есть баги. Баги — это плохо. Чтобы багов не было, нужно писать очень качественный код (это не в этой статье) и главное, тестировать его. Но мы пишем код, дополняем, рефакторим… И каждый раз поддавать каждую версию проекта одному и тому же набору тестов — неприятно. И тут один очень мудрый программист додумался сделать такую программу, которая могла бы тестировать вашу программу этим, заветным набором тестов. И эта модель тестирования называется — юнит-тестинг!

Unit-testing в Qt


А теперь конкретнее. В Qt за юнит-тестирование отвечает модуль QTestLib (testlib). Он предоставляет нам набор макросов для тестирования. Но об этом позже. Есть несколько методов проведения тестов:
  • Завести тестовый проект в дочерней директории вашего проекта и тестировать в нем.
  • Тестировать макросом qExec(..) в основном проекте


Я чаще использую первый метод, второй — уродлив. Но сегодня я вам покажу на примере второго метода, а первый метод распишу сейчас.

Qt использует прикольную модель: один проект — один тест. Поэтому реализовываются тесты созданием проекта tests в дочерней директории tests основного проекта. В tests лежит класс реализующий тест основного класса. Принцип работы его вы узнаете позже, а основное отличие этого подхода лежит в способе запуска теста. Этот подход требует отсутствие main.cpp и наличие макроса Q_TEST_MAIN(Test_ClassName) в конце test_classname.cpp.

Задача


Предлагаю для примера, реализовать класс Smart, который будет работать с сравнением целых чисел. Что он конкретно будет делать? Реализуем метод int min(int, int), который будет возвращать меньшее число и int max(int, int), который вернет большее число.

Ну давайте уже!


Так. Заходим в Qt Creator. Создаем консольное приложение Qt. Добавляем модуль testlib и gui (надо для тестирования GUI) к .pro-файлу. Теперь можно начинать. Принято начинать с написания тестов, а потом уже самого класса, но я пожалуй отклонюсь от традиций. Будем писать класс Smart. Вам повезло, напишу его я. Вам надо только понять как он работает. Вот этот красавец:

smart.h
#ifndef SMART_H
#define SMART_H

#include <QObject>
#include <QStringList>

class Smart : public QObject
{
    Q_OBJECT
public:
    explicit Smart(QObject *parent, const QStringList& list);
    
public slots:
    int max(int a, int b);
    int min(int a, int b);

};

#endif // SMART_H


smart.cpp
#include "smart.h"

Smart::Smart(QObject *parent, const QStringList& list) :
    QObject(parent)
{
}

int Smart::max(int a, int b)
{
    if(a > b)
        return a;
    return b;
}

int Smart::min(int a, int b)
{
    if(a < b)
        return a;
    return b;
}


Тестирование QObject* классов


Класс готов. Самое время проверить как он работает! Для этого напишем класс который будет тестировать наш «умный» класс. Он будет называется Test_Smart.

test_smart.h
#ifndef TEST_SMART_H
#define TEST_SMART_H

#include <QObject>

class Test_Smart : public QObject
{
    Q_OBJECT
public:
    explicit Test_Smart(QObject *parent = 0);

private slots: // должны быть приватными
    void max(); // int max(int, int)
    
};

#endif // TEST_SMART_H


test_smart.cpp
#include <QTest>
#include "test_smart.h"
#include "smart.h"

Test_Smart::Test_Smart(QObject *parent) :
    QObject(parent)
{
}

void Test_Smart::max()
{
    Smart a;
    QCOMPARE(a.max(1,   0), 1);
    QCOMPARE(a.max(-1,  1), 1);
    QCOMPARE(a.max(4,   8), 8);
    QCOMPARE(a.max(0,   0), 0);
    QCOMPARE(a.max(1,   1), 1);
    QCOMPARE(a.max(-10,-5), -5);
}


Мы немного не дописали, но это не страшно. Еще успеем. Сейчас надо научится запускать наши тесты.

main.cpp
#include <QApplication>
#include <QTest>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include "test_smart.h"

using namespace std;

int main(int argc, char *argv[])
{
    freopen("testing.log", "w", stdout);
    QApplication a(argc, argv);
    QTest::qExec(new Test_Smart, argc, argv);
    return 0;
}


Компилируем…

testing.log
********* Start testing of Test_Smart *********
Config: Using QTest library 4.8.1, Qt 4.8.1
PASS   : Test_Smart::initTestCase()
PASS   : Test_Smart::max()
PASS   : Test_Smart::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of Test_Smart *********


Поверьте, это — самый лучший исход тестирования!

Но мы еще не протестировали один метод. Я его оставил, так как хочу показать на нем один прием тестирования. Я называю его просто — "табличка". Суть этого метода в том, чтобы не повторять код. Помните наш тестовый метод void max()? Там мы много раз повторяли один и тот же самый код (разве что с разными параметрами). Чтобы этого избежать, в Qt реализован метод — «табличка». А как он работает? Создаем метод method_data(), в нем проводим пару нехитрых операций, а потом загружаем все это макросом QFETCH(). Сейчас как раз время увидеть это все на практике!

Теперь пора добавить в test_smart.cpp реализацию нашей «таблички»:

void Test_Smart::min_data()
{
    QTest::addColumn<int>("first");
    QTest::addColumn<int>("second");
    QTest::addColumn<int>("result");

    QTest::newRow("min_data_1") << 1 << 0 << 0;
    QTest::newRow("min_data_2") << -1 << 1 << -1;
    QTest::newRow("min_data_3") << 4 << 8 << 4;
    QTest::newRow("min_data_4") << 0 << 0 << 0;
    QTest::newRow("min_data_5") << 1 << 1 << 1;
    QTest::newRow("min_data_6") << -10 << -5 << -10;
}

void Test_Smart::min()
{
    Smart a;
    QFETCH(int, first);
    QFETCH(int, second);
    QFETCH(int, result);
    QCOMPARE(a.min(first, second), result);
}


Теперь опять компилируем. Получаем вывод.

testing.log
********* Start testing of Test_Smart *********
Config: Using QTest library 4.8.1, Qt 4.8.1
PASS   : Test_Smart::initTestCase()
PASS   : Test_Smart::max()
PASS   : Test_Smart::min()
PASS   : Test_Smart::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped
********* Finished testing of Test_Smart *********


Теперь где-нибудь что-то неправильно сделаем. Например поменяем в Smart::min(..) поменяем < на >.
testing.log
********* Start testing of Test_Smart *********
Config: Using QTest library 4.8.1, Qt 4.8.1
PASS   : Test_Smart::initTestCase()
PASS   : Test_Smart::max()
FAIL!  : Test_Smart::min(data_1) Compared values are not the same
   Actual (a.min(first, second)): 1
   Expected (result): 0
   Loc: [test_smart.cpp(41)]
FAIL!  : Test_Smart::min(data_1) Compared values are not the same
   Actual (a.min(first, second)): 1
   Expected (result): -1
   Loc: [test_smart.cpp(41)]
FAIL!  : Test_Smart::min(data_1) Compared values are not the same
   Actual (a.min(first, second)): 8
   Expected (result): 4
   Loc: [test_smart.cpp(41)]
FAIL!  : Test_Smart::min(data_1) Compared values are not the same
   Actual (a.min(first, second)): -5
   Expected (result): -10
   Loc: [test_smart.cpp(41)]
PASS   : Test_Smart::cleanupTestCase()
Totals: 3 passed, 4 failed, 0 skipped
********* Finished testing of Test_Smart *********


Значит все хорошо).

Тестируем GUI


Иногда, а иногда даже очень часто, нам приходится тестировать графический интерфейс. В QTestLib это тоже реализовано. Давайте протестируем QLineEdit.

Вот как выглядит наш test_qlineedit.h:
#ifndef TEST_QLINEEDIT_H
#define TEST_QLINEEDIT_H

#include <QObject>

class Test_QLineEdit : public QObject
{
    Q_OBJECT
private slots: // должны быть приватными
    void edit();
    
};

#endif // TEST_QLINEEDIT_H


А вот как выглядит, тоже наш test_qlineedit.cpp:
#include <QtTest>
#include <QtGui>
#include "test_qlineedit.h"

void Test_QLineEdit::edit()
{
    QLineEdit a;
    QTest::keyClicks(&a, "abCDEf123-");

    QCOMPARE(a.text(), QString("abCDEf123-"));
    QVERIFY(a.isModified());
}


Пора поправить main.cpp:
#include <QApplication>
#include <QTest>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include "test_smart.h"
#include "test_qlineedit.h"

using namespace std;

int main(int argc, char *argv[])
{
    freopen("testing.log", "w", stdout);
    QApplication a(argc, argv);
    QTest::qExec(new Test_Smart, argc, argv);
    cout << endl;
    QTest::qExec(new Test_QLineEdit, argc, argv);
    return 0;
}


Теперь запускаем тестирование:
********* Start testing of Test_Smart *********
Config: Using QTest library 4.8.1, Qt 4.8.1
PASS   : Test_Smart::initTestCase()
PASS   : Test_Smart::max()
PASS   : Test_Smart::min()
PASS   : Test_Smart::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped
********* Finished testing of Test_Smart *********

********* Start testing of Test_QLineEdit *********
Config: Using QTest library 4.8.1, Qt 4.8.1
PASS   : Test_QLineEdit::initTestCase()
PASS   : Test_QLineEdit::edit()
PASS   : Test_QLineEdit::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of Test_QLineEdit *********


Вот мы и научились тестировать GUI. Тест показал что QLineEdit работает корректно)).

Аргументы тестирования


Опция Объяснение
-o filename Выведет результаты тестирования в файл filename
-silent Ограничить сообщения показом только предупреждений и ошибок
-v1 Отображать информацию о входе и и выходе тестовых методов
-v2 Дополняет опцию -v1 тем, что выводит сообщения для макросов QCOMPARE и QVERIFY
-vs Отображать каждый высланный сигнал и вызванный слот
-xml Осуществлять вывод всей информации в формате XML
-eventdelay ms Заставляем тест остановиться и подождать ms миллисекунд. Эта опция полезна для нахождения ошибок в элементах GUI

Всего того, что я вам сегодня расказал, точно хватит чтобы прямо сейчас начать тестировать свои Qt-приложения. Что я могу вам сказать? Все советы и пожелания для улучшения статьи прошу написать в комментариях — для меня это важно, так как это, надеюсь, не последняя моя статья.

Удачи и хорошого вам кода;)
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

75
    +57 surfers

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • aspect250
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции