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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 21.01.2013, 19:59   #1
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию CppUnit. Разработка ПО на C++ через тестирование

Приветствую, дорогие друзья!

В этой пошаговой инструкции опишу разработку ПО на С++ через тестирование на Window 7 в среде NetBeans 7.2

Данная инструкция базируется на следующих:

- Adding Unit Tests to a C Project - NetBeans IDE Tutorial http://netbeans.org/kb/docs/cnd/c-unit-test.html

- CND69UnitTests http://wiki.netbeans.org/CND69UnitTests

Прежде чем устанавливать CppUnit, нужно установить MinGW и MSYS.

Установка MinGW

Инструкция базируется на:

1) MinGW Compilers and Tools http://netbeans.org/community/releas...ons.html#mingw

2) сообщения от ysim из темы http://forums.netbeans.org/topic33206.html

- скачиваем MinGW: http://sourceforge.net/projects/mingw/

- устанавливаем MinGW. При установке выбираем:

-- 'C++ Compiler'

-- все остальные настройки установки - поумолчанию (путь установки оставить 'C:\MinGW')

- добавляем в переменную окружение PATH следующий путь: 'C:\MinGW\bin'

Установка MSYS

- скачиваем MSYS http://sourceforge.net/projects/ming...e_mirror=ignum

- устанавливаем MSYS. Во время установки нужно дать два положительный ответа (ввести y) и ввести путь к MinGW (c:/MinGW)

Установка CppUnit
- скачиваем CppUnit: http://sourceforge.net/projects/cppu...ar.gz/download

- копируем в домашний каталог MSYS скаченный архив 'cppunit-1.12.1.tar.gz' (в моём случае в 'C:\MinGW\msys\1.0\home\Ivan')

- запускаем 'C:\msys\1.0\msys.bat'

- в открывшемся терминале вводим команды:

tar -zxvf cppunit-1.12.1.tar.gz
cd cppunit-1.12.1
./configure
make
make install

- копируем файл 'libcppunit.a' из каталога 'C:\msys\1.0\local\lib' в каталог 'C:\MinGW\lib'

Установка NetBeans

- скачиваем и устанавливаем Java Development Kit (JDK): http://www.oracle.com/technetwork/ja...ads/index.html

- скачиваем и устанавливаем NetBeans C/C++: http://netbeans.org/downloads/index.html


Последний раз редактировалось 8Observer8; 21.01.2013 в 20:17. Причина: орфография
8Observer8 вне форума Ответить с цитированием
Старый 21.01.2013, 20:01   #2
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию Пример разработки ПО

Создание нового проекта в NetBeans и "функций-заглушек" для разрабатываемого класса

- запускаем NetBeans

- создаём новый проект. Для этого: в меню File выбираем New Project... -> C/C++ Application -> вводим имя проекта Sphere -> нажимаем кнопку Finish

- создаём class. Для этого: ПКМ (правая кнопка мыши) по проекту Sphere (на панели Projects слева) -> New -> C++ Class... -> вводим название класса Sphere -> нажимаем кнопку Finish

- код класса. Создаём "функции-заглушки". Все файлы проекта:

main.cpp
Код:
#include "Sphere.h"

int main(int argc, char** argv) {

    return 0;
}
Sphere.h
Код:
#ifndef SPHERE_H
#define	SPHERE_H

class Sphere {
public:
    Sphere();
    double calcArea(double r);
    double calcVolume(double r);
private:
    double area;
    double volume;
};

#endif	/* SPHERE_H */
Sphere.cpp
Код:
#include "Sphere.h"

Sphere::Sphere() {
    area = 0;
    volume = 0;
}

double Sphere::calcArea(double r) {
    return area;
}

double Sphere::calcVolume(double r) {
    return volume;
}
Создание тестов

- создаём файлы с тестами. Для этого: ПКМ по файлу 'Sphere.cpp' -> выбираем Create Test -> выбираем New CppUnit Test... -> ставим галочки напротив функций calcArea() и calcVolume() -> нажимаем кнопку Next -> нажимаем кнопку Finish



- подключаем инклуды. Для этого ПКМ по каталогу Test Files -> выбираем Properties -> в открывшемся окне, слева выбираем C++ Compiler -> справа, в поле Include Directories, указываем путь 'C:\msys\1.0\local\include' (при выборе пути, я выбрал абсолютный путь)



- устанавливаем ожидаемый результат и пишем функцию сравнения. Для этого заменяем фрагмент в файле 'newtestclass.cpp':

Код:
void newtestclass::testCalcArea() {
    double r;
    Sphere sphere;
    double result = sphere.calcArea(r);
    if (true /*check result*/) {
        CPPUNIT_ASSERT(false);
    }
}

void newtestclass::testCalcVolume() {
    double r;
    Sphere sphere;
    double result = sphere.calcVolume(r);
    if (true /*check result*/) {
        CPPUNIT_ASSERT(false);
    }
}
на следующий:
Код:
void newtestclass::testCalcArea() {
    Sphere sphere;
    double r = 5.0;
    double actual = sphere.calcArea(r);

    double expected = 314.159;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcVolume() {
    Sphere sphere;
    double r = 5.0;
    double actual = sphere.calcVolume(r);

    double expected = 523.599;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}
Примечание. Чтобы вместо CPPUNIT_ASSERT_DOUBLES_EQUAL выбрать другой вариант сравнения, нужно ПКМ по CPPUNIT_ASSERT_DOUBLES_EQUAL -> выбираем Navigate -> выбираем Go to Declaration/Definition. Далее откроется файл 'TestAssert.h', где можно выбрать, к примеру, CPPUNIT_ASSERT_EQUAL(expected, actual) - точное совпадение

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

Запуск тестов

- запускаем тесты. Для этого: в меню выбираем Run -> выбираем Test Project (Sphere)

Результаты тестирования "функций-заглушек"

- смотрим на результаты тестирования. Ни один тест не дал положительного результата. Так как функции вернули нам нули. Как следствие, ожидаемые результаты не совпали с результатами работы функций: calcArea() и calcVolume()



Реализация функционала "функций-заглушек" разрабатываемого класса

- pеализуем функционал (я намеренно сделал ошибку в функции расчёта объёма: надо возводить в куб, а не в квадрат)

Sphere.cpp
Код:
#include "Sphere.h"
#include <cmath>

Sphere::Sphere() {
    area = 0;
    volume = 0;
}

double Sphere::calcArea(double r) {
    area = 4.0 * M_PI * pow(r, 2.0);
    return area;
}

double Sphere::calcVolume(double r) {
    volume = (4.0/3.0) * M_PI * pow(r, 2.0);
    return volume;
}
Результаты тестирования функций класса

- запускаем тесты (Alt+F6)

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



- исправляем ошибку:
Sphere.cpp
Код:
#include "Sphere.h"
#include <cmath>

Sphere::Sphere() {
    area = 0;
    volume = 0;
}

double Sphere::calcArea(double r) {
    area = 4.0 * M_PI * pow(r, 2.0);
    return area;
}

double Sphere::calcVolume(double r) {
    volume = (4.0/3.0) * M_PI * pow(r, 3.0);
    return volume;
}
- запускаем тестирование (Alt+F6). Видим, что ошибок нет:



Класс готов к использованию!

Далее бонус.

Сохраняем файлы проекта в Git репозитарий

- выбираем в меню Team -> выбираем Git -> выбираем Initialize -> выбираем путь

- выделяем файлы проекта -> выбираем в меню Team -> выбираем Commit...

- в поле Commit Message вводим текст (описание изменений и/или исправлений ошибок)

- в поле Author пишем автора проекта

- в поле Commiter пишем, кем внесены изменения в проект

- отмечаем файлы в которые внесены изменения

- нажимаем кнопку Commit



О возможностях Git в NetBeans можно почитать по следующей ссылке (на примере java проекта): Git User Guide - NetBeans IDE Tutorial http://netbeans.org/kb/docs/ide/git.html

Последний раз редактировалось 8Observer8; 21.01.2013 в 20:21. Причина: орфография
8Observer8 вне форума Ответить с цитированием
Старый 21.01.2013, 23:10   #4
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Добавление тестов

- открываем файл 'newtestclass.h' и добавляем тесты:

newtestclass.h
Код:
#ifndef NEWTESTCLASS_H
#define	NEWTESTCLASS_H

#include <cppunit/extensions/HelperMacros.h>

class newtestclass : public CPPUNIT_NS::TestFixture {
    CPPUNIT_TEST_SUITE(newtestclass);

    CPPUNIT_TEST(testCalcArea);
    CPPUNIT_TEST(testCalcVolume);
    CPPUNIT_TEST(testCalcArea_6);
    CPPUNIT_TEST(testCalcVolume_6);
    CPPUNIT_TEST(testCalcArea_7);
    CPPUNIT_TEST(testCalcVolume_7);
    CPPUNIT_TEST(testCalcArea_8);
    CPPUNIT_TEST(testCalcVolume_8);

    CPPUNIT_TEST_SUITE_END();

public:
    newtestclass();
    virtual ~newtestclass();
    void setUp();
    void tearDown();

private:
    void testCalcArea();
    void testCalcVolume();
    void testCalcArea_6();
    void testCalcVolume_6();
    void testCalcArea_7();
    void testCalcVolume_7();
    void testCalcArea_8();
    void testCalcVolume_8();

};

#endif	/* NEWTESTCLASS_H */
- открываем файл 'newtestclass.cpp' и добавляем тесты:

newtestclass.cpp
Код:
#include "newtestclass.h"
#include "Sphere.h"

CPPUNIT_TEST_SUITE_REGISTRATION(newtestclass);

newtestclass::newtestclass() {
}

newtestclass::~newtestclass() {
}

void newtestclass::setUp() {
}

void newtestclass::tearDown() {
}

void newtestclass::testCalcArea() {
    Sphere sphere;
    double r = 5.0;
    double actual = sphere.calcArea(r);

    double expected = 314.159;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcVolume() {
    Sphere sphere;
    double r = 5.0;
    double actual = sphere.calcVolume(r);

    double expected = 523.599;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcArea_6() {
    Sphere sphere;
    double r = 6.0;
    double actual = sphere.calcArea(r);

    double expected = 452.389;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcVolume_6() {
    Sphere sphere;
    double r = 6.0;
    double actual = sphere.calcVolume(r);

    double expected = 904.779;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcArea_7() {
    Sphere sphere;
    double r = 7.0;
    double actual = sphere.calcArea(r);

    double expected = 615.752;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcVolume_7() {
    Sphere sphere;
    double r = 7.0;
    double actual = sphere.calcVolume(r);

    double expected = 1436.755;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcArea_8() {
    Sphere sphere;
    double r = 8.0;
    double actual = sphere.calcArea(r);

    double expected = 804.2477;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}

void newtestclass::testCalcVolume_8() {
    Sphere sphere;
    double r = 8.0;
    double actual = sphere.calcVolume(r);

    double expected = 2144.661;
    double delta = 0.001;
    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
}
8Observer8 вне форума Ответить с цитированием
Старый 22.01.2013, 08:49   #5
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Извиняюсь за оффтоп.
хорошо, конечно, что ты такие большие (наверное интересные) посты пишешь..
но, думаю, лучше было бы помещать их сюда: http://pblog.ru/
мне кажется, это тот же programmersforum, но более подходящий тебе формат.
rrrFer вне форума Ответить с цитированием
Старый 27.08.2013, 23:30   #6
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Сложение двух чисел. Пример с исключениями

Задание. Написать функцию для сложения двух целых чисел. Первое число из диапазона [5, 10]. Второе число из диапазона [20, 30]. Если эти числа выходят за диапазон, то генерируем исключение. Функцию реализовать с использованием методологии TDD (сначала тесты - потом реализация)


Создаём новый проект в NetBeans.

- File -> New Project... -> C/C++ && C/C++ Application

- нажимаем кнопку Next

- в поле Project Name вводим имя проекта, к примеру: Sum

- нажимаем кнопку Finish


Создаём заглушку для разрабатываемой функции.

- в файле main.сpp пишем:

main.cpp
Код:
#include <stdexcept>

// a[5, 10]
// b[20, 30]
int sum(int a, int b) throw(std::out_of_range) {
    
}

int main(int argc, char** argv) {
    return 0;
}

Создаём тестовую площадку.

- нажимаем правой кнопкой мыши по файлу main.cpp

- выбираем Create Test -> New CppUnit Test

- ставим галочку перед sum(int, int)

- нажимаем кнопку Next

- нажимаем кнопку Finish


Указываем путь к заголовочным файлам и файлу библиотеки CppUnit.

- выбираем File -> Project Properties (имя проекта)

- выбираем C++ Compiler

- в поле Include Directories указываем путь к папке include CppUnit. В моём случае: C:/cppUnit/include

- выбираем Linker -> в поле Libraries указываем путь к библиотеке CppUnit (при добавлении откроется окно, где нужно будет нажать Add Library)

- нажимаем кнопку OK


Создаём несколько тестов.

- находим в файле newtestclass.cpp следующий код:

Код:
void newtestclass::testSum() {
    int a;
    int b;
    int result = sum(a, b);
    if (true /*check result*/) {
        CPPUNIT_ASSERT(false);
    }
}
Примечание. Чтобы найти нужное сравнение: нажимаем правой кнопкой мыши по CPPUNIT_ASSERT и выбираем Navigate -> Go to Declaration/Definition. Находим нужное сравнение.

- меняем его на следующий:

Код:
void newtestclass::testSum() {
    int a = 5;
    int b = 20;
    int actual = sum(a, b);
    int expected = 25;
    CPPUNIT_ASSERT_EQUAL(expected, actual);
}
Примечание. Нужно добавить:

Код:
#include <stdexcept>
- добавляем несколько тестов:

Код:
void newtestclass::testSum_01() {
    int a = 10;
    int b = 30;
    int actual = sum(a, b);
    int expected = 40;
    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testSum_02() {
    int a = 7;
    int b = 22;
    int actual = sum(a, b);
    int expected = 29;
    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testSum_03() {
    int a = 4;
    int b = 21;
    CPPUNIT_ASSERT_THROW(sum(a, b), std::out_of_range);
}

void newtestclass::testSum_04() {
    int a = 11;
    int b = 21;
    CPPUNIT_ASSERT_THROW(sum(a, b), std::out_of_range);
}

void newtestclass::testSum_05() {
    int a = 7;
    int b = 19;
    CPPUNIT_ASSERT_THROW(sum(a, b), std::out_of_range);
}

void newtestclass::testSum_06() {
    int a = 7;
    int b = 31;
    CPPUNIT_ASSERT_THROW(sum(a, b), std::out_of_range);
}
- заходим в файл newtestclass.h и добавляем код. Код теперь выглядит так:

newtestclass.h
Код:
#ifndef NEWTESTCLASS_H
#define	NEWTESTCLASS_H

#include <cppunit/extensions/HelperMacros.h>

class newtestclass : public CPPUNIT_NS::TestFixture {
    CPPUNIT_TEST_SUITE(newtestclass);

    CPPUNIT_TEST(testSum);
    CPPUNIT_TEST(testSum_01);
    CPPUNIT_TEST(testSum_02);
    CPPUNIT_TEST(testSum_03);
    CPPUNIT_TEST(testSum_04);
    CPPUNIT_TEST(testSum_05);
    CPPUNIT_TEST(testSum_06);

    CPPUNIT_TEST_SUITE_END();

public:
    newtestclass();
    virtual ~newtestclass();
    void setUp();
    void tearDown();

private:
    void testSum();
    void testSum_01();
    void testSum_02();
    void testSum_03();
    void testSum_04();
    void testSum_05();
    void testSum_06();
};

#endif	/* NEWTESTCLASS_H */
- запускаем тесты Alt+F6

- видим красную полосу (0% выполненных тестов; чтобы увидеть красную полосу - активируем окно редактора). Теперь наша задача сделать полосу зелёной (100% выполненных тестов).


Реализация разрабатываемой функции.

- реализуем функционал (частично):

Код:
// a[5, 10]
// b[20, 30]
int sum(int a, int b) throw (std::out_of_range) {
    if ((a < 5) || (a > 10) || (b < 20) || (b > 30)) {
        throw std::out_of_range("");
    }
}
- запускаем тесты Alt+F6

- видим, что красная полоса уменьшилась. Идём дальше

- реализуем функционал:

Код:
// a[5, 10]
// b[20, 30]
int sum(int a, int b) throw (std::out_of_range) {
    if ((a < 5) || (a > 10) || (b < 20) || (b > 30)) {
        throw std::out_of_range("");
    }
    
    return (a + b);
}
- запускаем тесты Alt+F6

- полоса стала зелёной! Задача выполнена!

Последний раз редактировалось 8Observer8; 27.08.2013 в 23:35.
8Observer8 вне форума Ответить с цитированием
Старый 27.08.2013, 23:32   #7
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Для реализаций функций нужно с помощью тестов описывать весь функционал (насколько это возможно). Когда функционал реализован (полоса полностью зелёного цвета) - можно приступить к рефакторингу (к улучшению кода), тогда тесты будут на страже нашего функционала. Мы будем уверены, что если мы испортим случайно функционал, то тесты нам это покажут (полоса перестанет быть полностью зелёной).
8Observer8 вне форума Ответить с цитированием
Старый 28.08.2013, 22:09   #8
Igor95
Форумчанин
 
Регистрация: 03.01.2013
Сообщений: 388
По умолчанию

Полезно. Спасибо :-)
Igor95 вне форума Ответить с цитированием
Старый 28.08.2013, 22:17   #9
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Цитата:
Сообщение от Igor95 Посмотреть сообщение
Полезно. Спасибо :-)
На здоровье

Пишите здесь любые вопросы. Буду рад обсудить
8Observer8 вне форума Ответить с цитированием
Старый 28.08.2013, 23:11   #10
Rififi
Старожил
 
Регистрация: 19.08.2009
Сообщений: 2,119
По умолчанию

тема интересная, только инструмент выбран неподходящий. CppUnit уже безнадежно устарел, и заброшен самими авторами. Трупик, короче.

По сравнению с GoogleTest, количество ненужного синтаксического мусора чтобы создать 1 тест, у CppUnit примерно в 3(!) раза больше.

к обоим фреймворкам можно добавлять расширения, чтобы сравнивать в ассертах свои типы данных с подробной распечаткой экспектов, но у Google больше матчеров в комплекте.
Ну и естессно у Гоогле есть GoogleMock - охренительная вещь- тут и CppUnit и Boost.Test в полном обломе.
Rififi вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Разработка, отладка, тестирование и документирование программ на Паскале Химия Помощь студентам 0 18.12.2011 23:19
статья - Test-Driven Development для Java(TDD, разработка через тестирование) на практике. Pblog Обсуждение статей 0 16.06.2011 23:10
Пользование cppunit? mike_tihomirov Общие вопросы C/C++ 0 15.04.2010 23:56
Тесты CPPUNIT Lazio Помощь студентам 0 13.12.2009 13:18
Разработка тестов CPPUNIT Lazio Фриланс 1 11.12.2009 00:55