Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Закрытая тема
Ваша тема закрыта, почему это могло произойти? Возможно,
Нет наработок или кода, если нужно готовое решение - создайте тему в разделе Фриланс и оплатите работу.
Название темы включает слова - "Помогите", "Нужна помощь", "Срочно", "Пожалуйста".
Название темы слишком короткое или не отражает сути вашего вопроса.
Тема исчерпала себя, помните, один вопрос - одна тема
Прочитайте правила и заново правильно создайте тему.
 
Опции темы Поиск в этой теме
Старый 11.09.2014, 17:58   #11
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,327
По умолчанию

Для таких мелких функций у меня почти всегда в проекте есть отдельный модуль - это файлы: "freeFunctions.h" и "freeFunctions.cpp". Туда складываю функции, для которых пока не придумал класс. Тестирую их Google Test'ом. А GUI, сеть, COM-порт т.д. только контент выдают. Выдачу контента легче контролировать, не прибегая к тестам, чем парсинг (этого контента) и обработка данных (полученных в результате парсинга). Тестами можно описать всякие граничные условия, острые моменты, исключения (когда выдаются, а когда нет). А потом приступить к разработки функции, не боясь чего-то не учесть. На практике, правда, лично у меня далеко не всегда хватает времени на тесты. По ощущениям, затраченное время на тесты, потом окупается. Но через GUI - для меня это слишком

Последний раз редактировалось 8Observer8; 11.09.2014 в 18:22.
8Observer8 вне форума
Старый 11.09.2014, 18:48   #12
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

FitCpp не пробовал? - это порт фитнеси на С++. Последние 2 книги, которые читал описывают юнит-тестирование именно с фитнеси... Вроде как все гладко там, а основная фича в том, что это вики-система, и тесты разворачиваются в вики и там же можно описать еще что-то, типа документации, наверное. Вот ссыль на описание порта для С++: http://accu.org/index.php/articles/305

Лично я не пробовал ни это, ни тесты гугла, мне кажется что для Qt гораздо удобнее использовать встроенные тесты - там и с GUI проблем нет и со всякими встроенными типами (которые иначе придется как-то кастовать в строки наверное). Да и вообще....

Почему ты используешь тесты гугла?
rrrFer вне форума
Старый 11.09.2014, 19:45   #13
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,327
По умолчанию

Цитата:
Сообщение от rrrFer Посмотреть сообщение
Почему ты используешь тесты гугла?
QTest очень непродуманный. Там нельзя тестировать вещественные значения и исключения. Google Test гораздо популярнее, богаче и не привязан к среде.
8Observer8 вне форума
Старый 11.09.2014, 20:24   #14
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Цитата:
Google Test гораздо популярнее, богаче и не привязан к среде.
Ну, то, что гегл не привязан к среде - это ИМХО минус если ты используешь Qt - твоя программа уже "привязана" к библиотеке, какой смысл хвастаться тем, что тесты от этой библиотеки не зависят? Как тестировать сигналы тестами гугла? - никак.

Цитата:
QTest очень непродуманный. Там нельзя тестировать вещественные значения и исключения.
Что такое "тестировать вещественные значения" ?
Ты наверное знаешь что
Код:
float a = 2, b = sqrt(4);
if (a != b) cout << "1";
else cout << "2";
выведет 1. Вот и в Qt аналогично, если ты хочешь сравнивать дробные - юзай qFuzzyCompare. Если гугл сравнивает как-то иначе - ИМХО это их косяк (но я не верю что может быть иначе).

Нашел в документации, цитирую:
Цитата:
Макрос QCOMPARE сравнивает фактическое значение actual с ожидаемым значением expected при помощи оператора равенства. Если actual и expected идентичны, то выполнение продолжается. Если нет, то в журнал теста записывается неудача, а тест далее не выполняется.

В случае сравнения вещественных чисел одинарной и двойной точности (float и double) для сравнения используется qFuzzyCompare(). Это означает, что сравнение с 0, вероятно, будет неудачным. Одним из решений этого является сравнение с 1 и добавление 1 к производимому выводу.
По исключениям ты тоже не прав. Тестировать было всегда можно, но раньше руками дописывали небольшой макрос (один раз на проект).

Ну а сейчас это не нужно, ведь есть там встроенная штука - QVERIFY_EXCEPTION_THROWN. В документации: http://qt-project.org/doc/qt-5/qtest...CEPTION_THROWN
Цитата:
The QVERIFY_EXCEPTION_THROWN macro executes an expression and tries to catch an exception thrown from the expression. If the expression throws an exception and its type is the same as exceptiontype or exceptiontype is substitutable with the type of thrown exception (i.e. usually the type of thrown exception is publically derived from exceptiontype) then execution will be continued. If not-substitutable type of exception is thrown or the expression doesn't throw an exception at all, then a failure will be recorded in the test log and the test won't be executed further.

Note: This macro can only be used in a test function that is invoked by the test framework.
А тут, например, можно посмотреть примеры использования: https://qt.gitorious.org/qt/qtbase/s...tionthrown.cpp

Короче все там есть. Но если и не было год назад - руками решалось все в 10-15 строк кода.
rrrFer вне форума
Старый 11.09.2014, 20:49   #15
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,327
По умолчанию

Ты думаешь в QTest есть тестирование сигналов? Да, у меня и нет такой необходимости.

По qFuzzyCompare ты не найдёшь нигде информацию, как её использовать. Как и по QVERIFY_EXCEPTION_THROWN

По GTest гораздо больше информации, вопросов на форумах и т.д. По QTest - приктически ничего.

Здесь видно, как легко использовть GTest: http://www.prog.org.ru/index.php?top...4714#msg194714

Последний раз редактировалось 8Observer8; 11.09.2014 в 20:53.
8Observer8 вне форума
Старый 11.09.2014, 20:55   #16
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,327
По умолчанию

Это всё в теории на самом деле на QTest невозможно писать нормально тесты. Точнее можно, но с костылями.
8Observer8 вне форума
Старый 11.09.2014, 21:25   #17
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Цитата:
Ты думаешь в QTest есть тестирование сигналов? Да, у меня и нет такой необходимости.
Да я знаю что есть. И примеров тьма. В гугле то спросить можно.
http://qt-project.org/doc/qt-5/QSignalSpy.html
Код:
QCheckBox *box = ...;
QSignalSpy spy(box, SIGNAL(clicked(bool)));

// do something that triggers the signal
box->animateClick();

QCOMPARE(spy.count(), 1); // make sure the signal was emitted exactly one time
QList<QVariant> arguments = spy.takeFirst(); // take the first signal

QVERIFY(arguments.at(0).toBool() == true); // verify the first argument
Это тестирование сигналов было (сверху).

Цитата:
По qFuzzyCompare ты не найдёшь нигде информацию, как её использовать.
Почему? - в документации и где угодно, функция используется прям постоянно. Просто вместо a == b пиши qFuzzyCompare(a, b) и все. Есть там артефакт, если один из аргументов равен нулю, связан с тем, что в плюсах ноль кастуется в указатель, насколько я понимаю. Это фича плюсов собственно.

Цитата:
Как и по QVERIFY_EXCEPTION_THROWN
Я выше ссылку привел, там тьма примеров, неужели мало? )
rrrFer вне форума
Старый 11.09.2014, 21:30   #18
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,327
По умолчанию

Я просто помучился с QTest и когда стал использовать GTest, то увидел, как это здорово, понятно, универсально, удобно и т.д.

Вот на примере первой задачи "Медиана". Функцию для расчёта медианы убираем в отдельный файл:

Код:
#ifndef FREEFUNCTIONS_H
#define FREEFUNCTIONS_H

#include "IncorrectArgument.h"

double median( double a, double b, double c )
throw( IncorrectArgument );

#endif // FREEFUNCTIONS_H
Код:

#include <cmath>
#include "freeFunctions.h"

double median( double a, double b, double c )
throw( IncorrectArgument )
{
//    double exp1 = 2.0 * b * b + 2.0 * c * c;
//    double exp2 = a * a;
//    if ( exp2 > exp1 ) {
//        // Выбросить исключение (то есть сообщение об ошибке)
//    }

//    return std::sqrt( exp1 - exp2  ) / 2.0;

    return 0.0;
}
Создаём новый пустой проект. Вот содержимое проекта для тестирования функции median():

Подключаем Google Test и файлы с функцией:

Median_Tests.pro
Код:

INCLUDEPATH += "C:/GTEST/gtest-1.7.0/include"
LIBS += "C:/GTEST/lib/libGoogleTest.a"

INCLUDEPATH += "../../"

HEADERS += \
    ../../freeFunctions.h

SOURCES += \
    ../../freeFunctions.cpp \
    main.cpp
Такие тесты:

main.cpp
Код:

#include "gtest/gtest.h"
#include "freeFunctions.h"

TEST( test001, normalTest )
{
    // Input
    double a = 5.0;
    double b = 7.0;
    double c = 10.0;

    // Actual
    double actual;
    ASSERT_NO_THROW( {
                        actual = median( a, b, c );
                     } );

    // Expected
    double expected = 8.261;

    // Delta
    double delta = 0.001;

    // Check
    ASSERT_NEAR( expected, actual, delta );
}

TEST( test002, incorrectArgumentTest )
{
    // Input
    double a = 10.0;
    double b = 1.0;
    double c = 1.0;

    // Actual
    ASSERT_THROW( {
                      double actual = median( a, b, c );
                  }, IncorrectArgument );
}

int main( int argc, char *argv[] )
{
    ::testing::InitGoogleTest( &argc, argv );
    return RUN_ALL_TESTS();
}
В первом тесте нормальный исход. При нормальных входных данных не должно быть исключений ASSERT_NO_THROW и мы сравниваем ожидаемый и актуальный результат с погрешностью delta.

Во втором тесте функция должна выбросить исключение IncorrectArgument (но мы конечно не написали ещё и поэтому получаем фейл)

Получаем такой результат:
Цитата:
The difference between expected and actual is 8.2609999999999992, which exceeds delta, where
expected evaluates to 8.2609999999999992,
actual evaluates to 0, and
delta evaluates to 0.001.

Expected: { double actual = median( a, b, c ); } throws an exception of type IncorrectArgument.
Actual: it throws nothing.

Последний раз редактировалось 8Observer8; 11.09.2014 в 21:39.
8Observer8 вне форума
Старый 11.09.2014, 21:37   #19
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,327
По умолчанию

Цитата:
Просто вместо a == b пиши qFuzzyCompare(a, b) и все.
Бесполезная штука, так как сравнивают всегда с delta. С помощью delta можно указать в каком знаке после запятой мы требуем отличие, например, на единицу: 0.0001 или 0.001 и т.д.
8Observer8 вне форума
Старый 11.09.2014, 22:26   #20
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Ну... с Qt оно делается также если не более элегантно. Единственное, что qFuzzyCompare сравнивает с фиксированной точностью и она выше чем 0.001, ну если уж очень надо - можно впилить свою (как я и сделал тут).

median.h:
Код:
#ifndef MEDIAN_H
#define MEDIAN_H

class IncorrectArgument {};
double median(double a, double b, double c) throw(IncorrectArgument);

#endif // MEDIAN_H
median.cpp:
Код:
#include "median.h"
#include <QtCore/QtMath>

double median(double a, double b, double c) throw(IncorrectArgument) {
  return 0.;
}
testmedian.cpp:
Код:
#include "median.h"
#include <QtTest/QtTest>

Q_DECL_CONSTEXPR static inline bool qFuzzyCompare(float p1, float p2, float accuracy) {
  return (qAbs(p1 - p2) / accuracy <= qMin(qAbs(p1), qAbs(p2)));
}

class TestMedian: public QObject{
Q_OBJECT
private slots:
  void normalTest();
  void incorrectArgumentTest();
};

void TestMedian::normalTest(){
  QCOMPARE(qFuzzyCompare(median(5, 7, 10), 8.261, 0.001), true);
}

void TestMedian::incorrectArgumentTest() {
   QVERIFY_EXCEPTION_THROWN(median(10, 1, 1), IncorrectArgument);
}

QTEST_MAIN(TestMedian)
#include "testmedian.moc"
Вывод:
Цитата:
********* Start testing of TestMedian *********
Config: Using QtTest library 5.3.1, Qt 5.3.1
PASS : TestMedian::initTestCase()
FAIL! : TestMedian::normalTest() Compared values are not the same
Actual (qFuzzyCompare(median(5, 7, 10), 8.261, 0.001)): 0
Expected (true) : 1
Loc: [../test/testmedian.cpp(16)]
FAIL! : TestMedian::incorrectArgumentTest() Expected exception of type IncorrectArgument to be thrown but no exception caught
Loc: [../test/testmedian.cpp(20)]
PASS : TestMedian::cleanupTestCase()
Totals: 2 passed, 2 failed, 0 skipped
********* Finished testing of TestMedian *********
Правим median.cpp:
Код:
double median(double a, double b, double c) throw(IncorrectArgument) {
  double exp1 = 2.0 * b * b + 2.0 * c * c;
  double exp2 = a * a;
  if ( exp2 > exp1 ) {
    throw IncorrectArgument();
  }

  return qSqrt( exp1 - exp2  ) / 2.0;
}
Цитата:
********* Start testing of TestMedian *********
Config: Using QtTest library 5.3.1, Qt 5.3.1
PASS : TestMedian::initTestCase()
PASS : TestMedian::normalTest()
PASS : TestMedian::incorrectArgumentTest()
PASS : TestMedian::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped
********* Finished testing of TestMedian *********
Короче я проблем не вижу

Последний раз редактировалось rrrFer; 11.09.2014 в 22:31.
rrrFer вне форума
Закрытая тема


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Помощь в решении задач. (Pascal) Ignoree Помощь студентам 2 27.04.2014 20:27
Ошибки в решении задач с функциями Anwen Помощь студентам 1 04.12.2010 16:23
Помощь в решении задач на Pascal. Girl_night Помощь студентам 1 15.10.2009 16:39