Учимся параметризировать тесты в junit

XFail: маркируем тесты, которые должны упасть¶

Маркер используется для пометки ожидаемо падающих тестов:

@pytest.mark.xfail
def test_function():
    ...

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

Маркировку можно установить непосредственно в функции (или в «setup»-фикстуре):

def test_function():
    if not valid_config():
        pytest.xfail("failing configuration (but should work)")
def test_function2():
    import slow_module

    if slow_module.slow_function():
        pytest.xfail("slow_module taking too long")

Эти два примера иллюстрируют ситуации, в которых вы не хотите проверять условие на уровне модуля.

Обратите внимание, что в случае вызова
(в отличие от маркировки с помощью ) код, расположенный
после этого вызова, выполняться не будет. Это происходит потому, что внутренне метод
реализуется путем создания определенного исключения

Параметр

Ни , ни по умолчанию не приводят к падению всего набора тестов.
Но это можно изменить, установив параметру значение :

@pytest.mark.xfail(strict=True)
def test_function():
    ...

В этом случае, если тест будет неожиданно пройден (), то это приведет
к падению всего тестового набора.

Значение по умолчанию параметра можно изменить в настройках
(в файле«pytest.ini«), используя опцию :

xfail_strict=true

Параметр

Так же, как и при использовании , можно установить зависимость
маркировки от определенного условия:

@pytest.mark.xfail(sys.version_info >= (3, 6), reason="python3.6 api changes")
def test_function():
    ...

Параметр

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

@pytest.mark.xfail(raises=RuntimeError)
def test_function():
    ...

В этом случае тест будет объявлен в отчете, как обычный сбой,
если он не выполняется с исключением, упомянутом в параметре .

Параметр

Если тест должен быть помечен и учитываться в отчете как маркированный ,
но при этом даже не должен выполняться, можно установить параметр в значение :

@pytest.mark.xfail(run=False)
def test_function():
    ...

Это особенно полезно для тестов , которые приводят к сбою интерпретатора
и должны быть исследованы позже.

Игнорирование

Используя параметр , можно принудительно запускать и выполнять тесты,
помеченные , как обычные непомеченные тесты:

pytest --runxfail

В этом случае метод также будет игнорироваться.

Зависимости тестов

PHPUnit поддерживает объявление явных зависимостей между тестовыми методами.
Эти зависимости не определяют порядок, в котором должны выполняться тестовые методы,
но они позволяют возвращать экземпляр (данные) фикстуры теста, созданные поставщиком (producer)
для передачи его зависимым потребителям (consumers).

  • Поставщик — тестовый метод, который предоставляет свой тестируемый модуль в качестве возвращаемого значения.
  • Потребитель — тестовый метод, который зависит от одного или более поставщиков и их возвращаемых значений.

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

Пример 2.2 Использование аннотации для описания зависимостей

<?php
use PHPUnit\Framework\TestCase;

class StackTest extends TestCase
{
    public function testEmpty()
    {
        $stack = [];
        $this->assertEmpty($stack);

        return $stack;
    }

    /**
     * @depends testEmpty
     */
    public function testPush(array $stack)
    {
        array_push($stack, 'foo');
        $this->assertSame('foo', $stackcount($stack)-1]);
        $this->assertNotEmpty($stack);

        return $stack;
    }

    /**
     * @depends testPush
     */
    public function testPop(array $stack)
    {
        $this->assertSame('foo', array_pop($stack));
        $this->assertEmpty($stack);
    }
}

В вышеприведённом примере первый тест, ,
создаёт новый массив и утверждает, что он пуст. Затем тест возвращает фикстуру
в качестве результата. Второй тест, ,
зависит от и ему передаётся результат этого зависимого теста
в качестве аргумента. Наконец,
зависит от .

Примечание

Возвращаемое значение, предоставленное поставщиком, по умолчанию передаётся потребителям «как есть».
Это означает, что когда поставщик возвращает объект, ссылка на этот объект передаётся потребителям.
Вместо ссылки возможна, либо (а) (глубокая) копия через или (б)
(поверхностная) копия (на основе ключевого слова PHP ) через
.

Чтобы быстро находить дефекты, нам нужно сосредоточить внимание
на соответствующих неудачных тестах. Вот почему PHPUnit пропускает выполнение теста,
когда зависимый тест (тест с зависимостью) провалился (не прошёл).
Это помогает локализовать дефекты за счёт использования зависимостей между тестами, как это показано
в

Пример 2.3 Использование зависимостей между тестами

<?php
use PHPUnit\Framework\TestCase;

class DependencyFailureTest extends TestCase
{
    public function testOne()
    {
        $this->assertTrue(false);
    }

    /**
     * @depends testOne
     */
    public function testTwo()
    {
    }
}
$ phpunit --verbose DependencyFailureTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.

FS

Time: 0 seconds, Memory: 5.00Mb

There was 1 failure:

1) DependencyFailureTest::testOne
Failed asserting that false is true.

/home/sb/DependencyFailureTest.php:6

There was 1 skipped test:

1) DependencyFailureTest::testTwo
This test depends on "DependencyFailureTest::testOne" to pass.

FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.

У теста может быть несколько аннотаций .
PHPUnit не изменяет порядок выполнения тестов, поэтому вы должны убедиться,
что все зависимости действительно могут быть выполнены до запуска теста.

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

Пример 2.4 Тест с несколькими зависимостями

<?php
use PHPUnit\Framework\TestCase;

class MultipleDependenciesTest extends TestCase
{
    public function testProducerFirst()
    {
        $this->assertTrue(true);
        return 'first';
    }

    public function testProducerSecond()
    {
        $this->assertTrue(true);
        return 'second';
    }

    /**
     * @depends testProducerFirst
     * @depends testProducerSecond
     */
    public function testConsumer($a, $b)
    {
        $this->assertSame('first', $a);
        $this->assertSame('second', $b);
    }
}

Справка

  • 21 Умно! Это мое любимое решение, так как оно использует встроенные функции bash. Спасибо за публикацию! @San, это две вложенные обрезки строк. Например., обрезал бы все с конца, вернув ведущий . Subbing с участием говорит ему «найти первый непробельный символ, затем стереть его и все после». С помощью вместо того делает операцию обрезки с конца жадной. Это вложено в нежадную обрезку с начала, поэтому, по сути, вы обрезаете от начала. Затем поменяйте местами%, # и * на конечные пробелы. Бац!
  • 2 Я не обнаружил никаких нежелательных побочных эффектов, и основной код работает и с другими оболочками, подобными POSIX. Однако в Solaris 10 он не работает с (только с , но это не то, что будет использоваться с обычными скриптами sh).
  • 11 Намного лучшее решение, чем использование sed, tr и т. Д., Поскольку оно намного быстрее, без использования fork (). На Cygwin разница в скорости на порядки.
  • 9 @San Сначала я был в тупике, потому что думал, что это регулярные выражения. Они не. Скорее, это синтаксис сопоставления с образцом (gnu.org/software/bash/manual/html_node/Pattern-Matching.html, wiki.bash-hackers.org/syntax/pattern), используемый при удалении подстроки (tldp.org/LDP/abs /html/string-manipulation.html). Так говорит «удалить из самая длинная подстрока, начинающаяся с символа, отличного от пробела «. Это означает, что вам останется только начальный пробел, который вы впоследствии удалите с помощью . Следующая строка (завершающая) противоположна.
  • 16 Это в подавляющем большинстве случаев идеальное решение. Разветвление одного или нескольких внешних процессов (например, , , , ) просто обрезать пробелы из одной строки в корне безумие , особенно когда большинство оболочек (включая bash) уже предоставляет встроенные средства преобразования строк прямо из коробки.

Bash имеет функцию под названием расширение параметра, который, помимо прочего, позволяет заменять строки на основе так называемого узоры (шаблоны напоминают регулярные выражения, но имеют принципиальные отличия и ограничения). &lsqb;исходная строка flussence: Bash имеет регулярные выражения, но они хорошо скрыты:&rsqb;

Ниже показано, как удалить все пустое пространство (даже изнутри) от значения переменной.

  • 2 Вернее, это работает для пробелов в середине var, но не когда я пытаюсь привязать его в конце.
  • Это помогает? Из справочной страницы: «$ {параметр / шаблон / строка} &lsqb;…&rsqb; Если шаблон начинается с%, он должен соответствовать в конце расширенного значения параметра.»
  • @Ant, значит, это не совсем регулярные выражения, а что-то похожее?
  • 3 Это регулярное выражение, просто странный диалект.
  • 14 удаляет первый пробел. удаляет все пробелы. Невозможно обрезать только начальные и конечные пробелы с помощью только этой конструкции.

Чтобы удалить все пробелы в начале и в конце строки (включая символы конца строки):

Это также удалит повторяющиеся пробелы:

Производит: ‘в этой строке много пробелов’

  • 5 Обычно xargs удаляет все разделители из строки. По умолчанию в качестве разделителя используется пробел (это можно изменить с помощью опции -d).
  • 4 Это, безусловно, самое чистое (как краткое, так и удобочитаемое) решение.
  • Зачем тебе совсем? имеет такой же вывод.
  • echo -n также удаляет конец строки

Стратификация (равномерное распределение) классов

Данное размышление заключается в следующем. Равномерно ли распределено количество классов в наборах данных, разделенных для обучения и тестирования?

Копировать

Это не равная разбивка. Главная идея заключается в том, получает ли наш алгоритм равные возможности для изучения признаков каждого из представленных классов и последующего тестирования результатов обучения, на равном числе экземпляров каждого класса

Хотя это особенно важно для небольших наборов данных, желательно постоянно уделять внимание данному вопросу

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

Копировать

Сейчас это выглядит лучше, и представленные числа говорят нам, что это наиболее оптимально возможное разделение.

Как разделить набор данных, используя Sklearn?

Посмотрим, как мы можем использовать Sklearn, чтобы разделить набор данных на наборы тренировки и тестирования. Мы будем перейти на процесс шаг за шагом.

1. Импортируйте набор данных

Давайте начнем, импортируя набор данных в нашу ноутбук Python. В этом руководстве мы собираемся использовать набор данных Titian в качестве набора данных. Вы можете импортировать набор данных Титаника из Библиотека морской библиотеки в питоне.

import seaborn as sns
titanic = sns.load_dataset('titanic')
titanic.head()

2. Форма ввода и выходных векторов из набора данных

Прежде чем перейти к разделению набора данных на наборы тренировок и тестирования, нам необходимо подготовить векторы ввода и вывода из набора данных.

Давайте лечить « выжил «Столбец как вывод. Это означает, что эта модель будет обучена предсказать, выживет ли человек, выживет или нет.

y = titanic.survived
print(y)

Выход:

Нам также нужно удалить ‘ выжил «Столбец из набора данных, чтобы получить вектор ввода.

x=titanic.drop('survived',axis=1)
x.head()

Выход:

3. Решив раскол соотношения

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

Наиболее распространенное расщепленное соотношение, используемое учеными данных, является 80:20.

Коэффициент разделения 80:20 означает, что 80% данных пойдут на учебный набор и 20% набора данных пойдут на набор тестирования.

4. Выполнение раскола

Разделить данные, которые мы будем использовать rain_test_split от библиотеки Sklearn.

rain_test_split Случайно распределяет ваши данные на набор тренировок и тестирования в соответствии с предоставленным соотношением.

Мы собираемся использовать 80:20 как раскол соотношения.

Нам сначала нужно импортировать rain_test_split от Sklearn.

from sklearn.model_selection import train_test_split

Для выполнения раскола использования:

x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2)

Мы упомянули размер теста как 0.2, это означает, что размер обучения составит 0,8, давая нам наше желаемое соотношение.

5. Проверьте, печать форм обучения и тестирования векторов

Чтобы проверить разделение, давайте расстегиваем формы разных векторов.

print("shape of original dataset :", titanic.shape)
print("shape of input - training set", x_train.shape)
print("shape of output - training set", y_train.shape)
print("shape of input - testing set", x_test.shape)
print("shape of output - testing set", y_test.shape)

Выход:

shape of original dataset : (891, 15)
shape of input - training set (712, 14)
shape of output - training set (712,)
shape of input - testing set (179, 14)
shape of output - testing set (179,)

Типы чистых пересечений rfc

Вы уже знаете о типах объединения в PHP 8.0, и типы пересечений представляют собой аналогичную функцию. Если для типов объединения требуется, чтобы входные данные были одного из заданных типов, для типов пересечений входные данные должны быть всех указанных типов. Типы пересечений особенно полезны, когда вы работаете с большим количеством интерфейсов:

Типы пересечений в настоящее время изначально не поддерживаются языком. Вместо этого нужно использовать аннотации phpdoc и/или использовать типизированные свойства , как показано в следующем примере:

Типы чистых пересечений, позволяют указать с использованием синтаксиса T1&T2&… и их можно использовать везде там, где в настоящее время принимаются типы:

Если вам нравится этот стиль программирования, вам нужно будет создать новый Sluggable интерфейс и реализовать его в $post, типы пересечений избавляются от этих накладных расходов.

Начинаем

Для начала нужно разбираться в Spring Boot и JUnit. 

Итак, с чем будем работать:

  • Spring Boot 2.5.3
  • Maven
  • JUnit 5
  • Java 8+

1.1. Добавляем зависимость JUnit

Настраиваем проект (возможно стоит ознакомиться с указаниями, как это делать), далее добавляем в pom.xml такие строчки:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-params</artifactId>
</dependency>

Первая из зависимостей включает не только JUnit, но и еще пару библиотек, которые которые могут понадобиться для тестирования нашего приложения: mockito и hamcrest. Hamcrest будет задействован для получения провайдеров аргументов (далее объясню, что это).

переобучения

Переоснащение означает, что обученная нами модель обучена «слишком хорошо» и теперь, ну, в общем, слишком близко подходит к набору данных для обучения. Это обычно происходит, когда модель слишком сложна (то есть слишком много признаков / переменных по сравнению с количеством наблюдений). Эта модель будет очень точной в отношении данных обучения, но, вероятно, будет очень неточной в отношении нетренированных или новых данных. Это потому, что эта модель не обобщена (или не обобщена как AS), что означает, что вы можете обобщать результаты и не делать никаких выводов для других данных, что, в конечном счете, является тем, что вы пытаетесь сделать. В основном, когда это происходит, модель изучает или описывает «шум» в обучающих данных вместо фактических отношений между переменными в данных. Этот шум, очевидно, не является частью какого-либо нового набора данных и не может быть применен к нему.

Бонус.

Можно кастомизировать отображаемое имя тестов. 

Как мы помним, в нашем тесте было:

@ParameterizedTest
    @CsvSource({
        "2, 3, 6",
        "0, 10, 0",
        "-5, 8, -40",
        "3, -10, -30",
        "-3, -13, 39"
    })
    void calculateTotalPriceShouldWorkGivenDifferentArguments(
      int productPrice, int quantity, int totalExpected) {
        int totalCalculated = example.calculateTotalPrice(productPrice, quantity);

        assertEquals(totalExpected, totalCalculated);
    }

При его запуске увидим следующее:

Вывод можно визуально приукрасить, следующими тегами:

  • {index}. Отображает итерацию (начинается с 1).
  • {0}, {1}. Отображает имя переменной. Применяется, когда есть несколько параметров.

Все что нужно сделать, это передать аргумент name внутри @parametrizedTest.

@ParameterizedTest(name = "Iteration #{index} -> Product Price = {0}, Quantity = {1} and the multiplication value is {2}")
    @CsvSource({
        "2, 3, 6",
        "0, 10, 0",
        "-5, 8, -40",
        "3, -10, -30",
        "-3, -13, 39"
    })
    void calculateTotalPriceShouldWorkGivenDifferentArguments(int productPrice, int quantity, int totalExpected) {
        int totalCalculated = example.calculateTotalPrice(productPrice, quantity);

        assertEquals(totalExpected, totalCalculated);
    }

Надеемся, материал был не только сложным, но и полезным. 

***

В.Нобрэ — тестировщик в компании PicPay (финтех)

Упражнения

In Chapter 5, Plugins, on page 95, you created a plugin called pytest-nice that included a —nice command-line option. Let’s extend that to include a pytest.ini option called nice.

В главе 5 «Плагины» на стр. 95 вы создали плагин с именем который включает параметр командной строки . Давайте расширим это, включив опцию под названием .

  1. Добавьте следующую строку в хук-функцию :
  2. Места в плагине, которые используют , также должны будут вызывать . Сделайте эти изменения.
  3. Проверьте это вручную, добавив в файл .
  4. Не забудьте про тесты плагинов. Добавьте тест, чтобы убедиться, что параметр из работает корректно.
  5. Добавьте тесты в каталог плагинов. Вам нужно найти некоторые .

Переменные средЫ

Давайте поговорим о переменных среды. Данные переменные, заданы в и инициализируются при загрузке, либо при выполнении команды «. .файл_инициализации». Обычно, основные значения переменных среды следующие:

$BASH

В переменной $BASH содержится полный путь до исполняемого файла командной оболочки Bash.

$BASH_VERSION

В переменную $BASH_VERSION записывается версия Bash.

$CDPATH

Переменная, которая хранит пути поиска каталога. (используется при вводе команды cd имя_каталога без слэша)

$CLASSPATH

содержит список каталогов для поиска файлов классов Java и архивов Java.

$HOME

домашний каталог текущего пользователя.

$HOSTNAME

В переменной $HOSTNAME хранится имя компьютера.

$HISTSIZE

количество событий, хранимых в истории за 1 сеанс

$HISTFILE

Расположение файла истории событий

$HISTFILESIZE

количество событий, хранимых в истории между сеансами

$IFS

переменная хранит символы, являющиеся разделителями команд и параметров. (по умолчанию — пробел, табуляция и новая строка)

$LANG

текущая установка локализации, которая позволяет настроить командную оболочку для использования в различных странах и на различных языках.

$MAIL

Место, где храниться почта

$OSTYPE

В переменной $OSTYPE содержится описание операционной системы.

$PATH

список каталогов для поиска команд и приложений, когда полный путь к файлу не задан.

$PS1

PS1 используется как основная строка приглашения. (то самое #)

$PS2

PS2 используется как вторичная строка приглашения.

$PROMPT_COMMAND

Эта команда должна быть выполнена до отображения строки приглашения Bash.

$PWD

полный путь к текущему рабочему каталогу.

$SHELL

полный путь к текущей командной оболочке.

$USER

В переменной $USER содержится имя текущего пользователя.

Случайное перемешивание строк

Первое, на что следует обратить внимание: перемешаны ли ваши экземпляры? Это следует делать пока нет причин не перетасовывать данные (например, они представляют собой временные интервалы). Мы должны убедиться в том, что наши экземпляры не разбиты на выборки по классам

Это потенциально вносит в нашу модель некоторую нежелательную предвзятость.

Например, посмотрите, как одна из версий набора данных iris, упорядочивает свои экземпляры при загрузке:

Копировать

Если такой набор данных с тремя классами при равном числе экземпляров в каждом разделить на две выборки: 2/3 для обучения и 1/3 для тестирования, то полученные поднаборы будут иметь нулевое пересечение классовых меток. Это, очевидно, недопустимо при изучении признаков для предсказания классов. К счастью, функция по умолчанию автоматически перемешивает данные (вы можете переопределить это, установив для параметра значение ).

  • В функцию должны быть переданы как вектор признаков, так и целевой вектор (X и y).
  • Для воспроизводимости вы должны установить аргумент .
  • Также необходимо определить либо , либо , но оба они не нужны. Если вы явно устанавливаете оба параметра, они должны составлять в сумме 1.

Вы можете убедится, что теперь наши классы перемешаны.

Копировать

Переменные пользователя

Присвоение значения переменной

Пользовательские переменные появляются, как только пользователь «объявит» данную переменную, то есть присвоит переменной какое-то значение:


$ var=»123 345″ # Присваивание значения переменной
# Если в значениях переменных встречаются пробелы,
# то использование кавычек обязательно, иначе — можно без кавычек.
$ variable=$var # Подстановка значения переменной
#————————————————————————-
# Использование пробельных символов
# с обеих сторон символа «=» присваивания недопустимо.
# Если записать «VARIABLE =value»,
# то интерпретатор попытается выполнить команду «VARIABLE» с параметром «=value».
# Если записать «VARIABLE= value»,
# то интерпретатор попытается установить переменную окружения «VARIABLE» в «»
# и выполнить команду «value».
#————————————————————————-
$ echo var    # Это НЕ вывод переменной
var
$ echo $var

123 345
$ echo $variable
123 345
$ echo «$variable»
123 345
# Как видно, использование кавычек при выводе значения переменной сохраняет
# пробельные символы в переменной
$ echo ‘$variable’
$variable
$ echo \$variable
$variable
# Внутри одинарных кавычек не производится подстановка значений переменных,
# т.е. «$» интерпретируется как простой символ

А так же при использовании
# символа экранирования.
$ variable=    # Запись пустого значения в переменную(!но не удаление)
$ echo $variable

#  Обратите внимание: запись пустого значения — это не то же самое,
# что сброс переменной, хотя конечный результат — тот же (см. ниже).
$ echo «uninitialized_variable = $uninitialized_variable»
uninitialized_variable = #пустое
# Неинициализированная переменная содержит «пустое» значение.
$ unset uninitialized_variable    # Сброс переменной.
$ echo «uninitialized_variable = $uninitialized_variable»
uninitialized_variable = #пустое

Действия над переменными

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

$ readonly variable    # пометка переменной "только для чтения"
$ variable=789
-bash: variable: доступная только на чтение переменная
$ cat test             #содержимое первого скрипта
#! /bin/bash
variable1=znachenie    #объявление переменной
echo "test 1: $variable1"      #вывод переменной
./subtest              #запуск вложенного скрипта
echo "test 2: $variable1"           #вывод переменной после запуска вложенного скрипта
export variable1       #экспорт переменной
echo "test 3: $variable1"
./subtest
echo "test 4: $variable1"
$ cat subtest          #содержимое скрипта, запускаемого из первого
#! /bin/bash
echo "subtest 1: $variable1"
variable1=drugoe
echo "subtest 2: $variable1"
$ ./test               #запуск скрипта
test 1: znachenie
subtest 1:
subtest 2: drugoe
test 2: znachenie
test 3: znachenie
subtest 1: znachenie
subtest 2: drugoe
test 4: znachenie
$ cat where
where=$(pwd)
echo "Вы работаете в каталоге 1: $where"
echo "Вы работаете в каталоге 2: $(pwd)"
where2=`pwd`
echo "Вы работаете в каталоге 3: $where2"
# Как видно, переменной можно присвоить значение вывода какой-либо команды
# используя комбинацию $(command) или `command` (апострофы).
$ ./where
Вы работаете в каталоге 1:  /home/user
Вы работаете в каталоге 2:  /home/user
Вы работаете в каталоге 3: /home/user

Полный код

Полный код для этого учебника приведен ниже:

import seaborn as sns
from sklearn.model_selection import train_test_split

#import dataset
titanic = sns.load_dataset('titanic')

#output vector
y = titanic.survived

#input vector
x=titanic.drop('survived',axis=1)

#split
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2)

#verify
print("shape of original dataset :", titanic.shape)
print("shape of input - training set", x_train.shape)
print("shape of output - training set", y_train.shape)
print("shape of input - testing set", x_test.shape)
print("shape of output - testing set", y_test.shape)

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

Qt Test – это среда для модульного тестирования кода на C++. Он является частью Qt, что означает, что он включает в себя функции для тестирования графического интерфейса и других элементов Qt, таких как сигналы, но его также можно использовать для тестирования простого (без Qt) кода на C++.

В данном руководстве я собираюсь объяснить, как использовать Qt Test для тестирования класса на C++. Это потребует создания проекта, определения модульного теста и использования различных макросов, доступных для тестирования кода.

Это первый пост из серии, посвященной Qt Test. Посты этой серии:

  • Модульное тестирование кода на C++ с помощью Qt Test. Часть1. Введение
  • Модульное тестирование кода на C++ с помощью Qt Test. Часть 2. Расширенное тестирование
  • Модульное тестирование GUI (графического интерфейса пользователя) с помощью Qt Test. Часть 1. Введение
  • Модульное тестирование GUI (графического интерфейса пользователя) с помощью Qt Test. Часть 2. Расширенное тестирование

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Создание улучшенного проекта

Как было показано в первом руководстве, философия Qt Test заключается в том, что каждый тестовый случай является независимым исполняемым файлом. В реальных проектах у вас обычно есть сотни или даже тысячи различных юнит-тестов, и запускать их все вручную определенно не лучший вариант. Лучший способ запускать их и управлять ими – это создать «родительский» проект. Правильный выбор в этом случае – шаблон «Проект с поддиректориями» (Subdirs Project), который находится в группе «Другой проект» (Other Project) диалогового окна «Новый проект» (New Project).

Рисунок 1 – Создание проекта с поддиректориями в Qt Creator

После создания проекта вы вернетесь в диалоговое окно выбора шаблона, чтобы создать первый проект в «родительском» проекте. Вы можете отказаться от этого и перейти к добавлению существующих проектов. В итоге вы получите что-то вроде этого:

Рисунок 2 – Проекты в Qt Creator

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

Почему мы должны разделить наш набор данных?

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

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

Преодоление – это случай, когда ваша модель представляет собой набор данных слишком точно. Это означает, что ваша модель слишком близко подходит.

Переоснащение – это нежелательное явление при обучении модели. Так подходит.

Подзадание – это когда модель даже не может представлять точки данных в тренировочном наборе данных.

Преобразование прописных и строчных букв в строку

Вы также можете преобразовать строку в строчные или прописные буквы. Сначала создадим две строки с именами легенда и актер:

legend="john nash"
actor="JULIA ROBERTS"

Вы можете преобразовать все буквы в строке легенды в верхний регистр:

Excelent@andreyex:~/scripts$ echo ${legend^^}
JOHN NASH

Вы также можете преобразовать все буквы в строке актера в нижний регистр:

Excelent@andreyex:~/scripts$ echo ${actor,,}
julia roberts

Вы также можете преобразовать только первый символ строки легенды в верхний регистр следующим образом:

Excelent@andreyex:~/scripts$ echo ${legend^}
John nash

Точно так же вы можете преобразовать только первый символ строки актера в нижний регистр следующим образом:

Excelent@andreyex:~/scripts$ echo ${actor,}
jULIA ROBERTS

Вы также можете изменить некоторые символы в строке на верхний или нижний регистр; например, вы можете изменить буквы jи nна верхний регистр в строке легенды следующим образом:

Excelent@andreyex:~/scripts$ echo ${legend^^}
JohN Nash

Вывод ошибки

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

Пример 2.16 Вывод ошибки, сгенерированный при неудачном сравнении массива

<?php
use PHPUnit\Framework\TestCase;

class ArrayDiffTest extends TestCase
{
    public function testEquality()
    {
        $this->assertSame(
            1, 2,  3, 4, 5, 6],
            1, 2, 33, 4, 5, 6
        );
    }
}
$ phpunit ArrayDiffTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.

F

Time: 0 seconds, Memory: 5.25Mb

There was 1 failure:

1) ArrayDiffTest::testEquality
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
 Array (
     0 => 1
     1 => 2
-    2 => 3
+    2 => 33
     3 => 4
     4 => 5
     5 => 6
 )

/home/sb/ArrayDiffTest.php:7

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

В этом примере только одно из значений массива отличается, а остальные значения показаны,
для обеспечения контекста, где произошла ошибка.

Когда сгенерированный вывод будет длинным для чтения, PHPUnit разделит его
и отобразит несколько строк контекста вокруг каждого несоответствия (разницы).

Пример 2.17 Вывод ошибки при неудачном сравнении длинного массива

<?php
use PHPUnit\Framework\TestCase;

class LongArrayDiffTest extends TestCase
{
    public function testEquality()
    {
        $this->assertSame(
            , , , , , , , , , , , , 1, 2,  3, 4, 5, 6],
            , , , , , , , , , , , , 1, 2, 33, 4, 5, 6
        );
    }
}
$ phpunit LongArrayDiffTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.

F

Time: 0 seconds, Memory: 5.25Mb

There was 1 failure:

1) LongArrayDiffTest::testEquality
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
     11 => 0
     12 => 1
     13 => 2
-    14 => 3
+    14 => 33
     15 => 4
     16 => 5
     17 => 6
 )

/home/sb/LongArrayDiffTest.php:7

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Крайние случаи

Когда сравнение терпит неудачу, PHPUnit создаёт текстовые представления
входных значений и сравнивает их. Благодаря этой реализации результат сравнения изменений (формат diff)
может показать больше проблем, чем существуют на самом деле.

Это происходит только при использовании или „слабых“ („weak“) функций
сравнения массивов или объектов.

Пример 2.18 Крайний случай в генерации сравнения при использовании слабого сравнения

<?php
use PHPUnit\Framework\TestCase;

class ArrayWeakComparisonTest extends TestCase
{
    public function testEquality()
    {
        $this->assertEquals(
            1, 2, 3, 4, 5, 6],
            '1', 2, 33, 4, 5, 6
        );
    }
}
$ phpunit ArrayWeakComparisonTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.

F

Time: 0 seconds, Memory: 5.25Mb

There was 1 failure:

1) ArrayWeakComparisonTest::testEquality
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    0 => 1
+    0 => '1'
     1 => 2
-    2 => 3
+    2 => 33
     3 => 4
     4 => 5
     5 => 6
 )

/home/sb/ArrayWeakComparisonTest.php:7

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

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

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: