Как создать программу для решения тестов

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

39 894 просмотров

В процессе написания ПО у меня возникло понимание о целесообразности применения unit-тестов.

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

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

Согласно данным[1] исследований, цена ошибки в ходе разработки и поддержании ПО экспоненциально возрастает при несвоевременном их обнаружении.

На представленном рисунке видно, что при выявлении ошибки на этапе формирования требований мы получим экономию средств в соотношении 200:1 по сравнению с их обнаружением на этапе поддержки.

Как написать любой онлайн тест на максимальный балл или 5 на дистанционке

Среди всех тестов львиную долю занимают именно unit-тесты. В классическом понимании unit-тесты позволяют быстро и автоматически протестировать отдельные части ПО независимо от остальных.

Рассмотрим простой пример создания unit-тестов. Для этого создадим консольное приложение Calc, которое умеет делить и суммировать числа.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Calc < class Program < static void Main(string[] args) < >> >

Добавляем класс, в котором будут производиться математические операции.

using System; namespace Calc < /// /// Выполнение простых математических действий над числами /// public class Calculator < /// /// Получаем результат операции деления (n1 / n2) /// /// Первое число /// Второе число /// Результат public double Div(double n1, double n2) < // Проверка деления на «0» if (n2 == 0.0D) throw new DivideByZeroException(); return n1 / n2; >/// /// Получаем результат сложения чисел и их увеличения на единицу /// /// /// /// public double AddWithInc(double n1, double n2) < return n1 + n2 + 1; >> >

Так, в методе Div производится операция деления числа n1 на число n2. Если передаваемое число n2 будет равняться нулю, то такая ситуация приведет к исключению. Для этого знаменатель этой операции проверяется на равенство нулю.

Метод AddWithInc производит сложение двух передаваемых чисел и инкрементацию полученного результата суммирования на единицу.

На следующем шаге добавим в решение проект тестов.

Пустой проект unit-тестов:

using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CalcTests < [TestClass] public class UnitTest1 < [TestMethod] public void TestMethod1() < >> >

Создание тестов для проведения экзаменов

Переименуем наш проект: «SimpleCalculatorTests». Добавляем ссылку на проект Calc.

В проекте Calc содержатся 2 метода, которые надо протестировать на корректность работы. Для этого создадим 3 теста, которые будут проверять операцию деления двух чисел, операцию деления на нуль и операцию сложения двух чисел и инкрементацию полученной суммы.

Добавляем в проект тест для проверки метода AddWithInc.

В тесте создаются 3 переменные — это аргументы, передаваемые в метод AddWithInc, и ожидаемый результат, возвращаемый этим методом. Результат выполнения метода будет записан в переменную result.

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

Следующим тестом мы будем проверять метод Div

[TestMethod] public void Div_4Div2_Returned2() < // arrange var calc = new Calculator(); double arg1 = 4; double arg2 = 2; double expected = 2; // act double result = calc.Div(arg1, arg2); // assert Assert.AreEqual(expected, result); >

Аналогичным образом создаются два аргумента и ожидаемый результат выполнения метода Div. Если результат деления 4/2 в методе равен 2, то тест считается пройдённым. В противном случае — не пройденным.

Следующий тест будет проверять операцию деления на нуль в методе Div.

[TestMethod] [ExpectedException(typeof(DivideByZeroException), «Oh my god, we can’t divison on zero»)] public void Div_4Div0_ZeroDivException() < // arrange var calc = new Calculator(); double arg1 = 4; double arg2 = 0; // act double result = calc.Div(arg1, arg2); // assert >

Тест будет считаться пройденным в случае возникновения исключения DivideByZeroException — деление на нуль. В отличии от двух предыдущих тестов, в этом тесте нет оператора Assert. Здесь обработка ожидаемого результата производится с помощью атрибута «ExpectedException».

Читайте также:
Программы для новичков программистов

Если аргумент 2 равен нулю, то в методе Divвозникнет исключение — деление на нуль. В таком случае тест считается пройденным. В случае, когда аргумент 2 будет отличен от нуля, тест считается проваленным.

Для запуска теста необходимо открыть окно Test Explorer. Для этого нажмите Test -> Windows -> Test Explorer (Ctrl+, T). В появившемся окне можно увидеть 3 добавленных теста:

Для запуска всех тестов нажмите Test -> Run -> All tests (Ctrl+, A).

Если тесты выполнятся успешно, в окне Test Explorer отобразятся зеленые пиктограммы, обозначающие успешность выполнения.

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

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

Случай написания тестов для бэкенда веб-приложения в моей практике является не совсем стандартным вариантом применения unit-тестов. В данной ситуации unit-тесты вызывали методы контроллера MVC-приложения, в то же время передавая тестовые данные в контроллеры.

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

Существуют случаи, когда модульные тесты применять нецелесообразно. Например, если вы веб-разработчик, который делает сайты, где мало логики. В таких случаях имеются только представления, как, например, для сайтов-визиток, рекламных сайтов, или, когда вам поставлена задача реализовать пилотный проект «на посмотреть, что получится». У вас ограниченные ресурсы и время. А ПО будет работать только один день — для показа руководству.

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

Для определения целесообразности использования unit-тестов можно воспользоваться следующим методом: возьмите лист бумаги и ручку и проведите оси X и Y. X — алгоритмическая сложность, а Y — количество зависимостей. Ваш код поделим на 4 группы.

  1. Простой код (без каких-либо зависимостей)
  2. Сложный код (содержащий много зависимостей)
  3. Сложный код (без каких-либо зависимостей)
  4. Не очень сложный код (но с зависимостями)

Первое — это случай, когда все просто и тестировать здесь ничего не нужно.

Второе — случай, когда код состоит только из плотно переплетенных в один клубок реализаций, перекрестно вызывающих друг друга. Тут неплохо было бы провести рефакторинг. Именно поэтому тесты писать в этом случае не стоит, так как код все равно будет переписан.

Третье — случай алгоритмов, бизнес-логики и т.п. Важный код, поэтому его нужно покрыть тестами.

Четвертый случай — код объединяет различные компоненты системы. Не менее важный случай.

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

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

[1] Данные взяты из книги «Технология разработки программного обеспечения» автора Ларисы Геннадьевны Гагариной

Источник: vc.ru

Пошаговое руководство. Разработка на основе тестирования с помощью обозревателя тестов

Область применения:yesVisual StudionoVisual Studio для Mac noVisual Studio Code

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

В данном пошаговом руководстве показано, как разработать тестируемый метод в C# с помощью платформы тестирования Microsoft (MSTest). Можно легко адаптировать его для других языков или других тестовых платформ, например NUnit. Дополнительные сведения см. в разделе Установка платформ модульного тестирования сторонних поставщиков.

Создание теста и создание кода

Новые проекты кода и тестов

  1. Создайте проекта C# Библиотека классов (.NET Standard). Данный проект будет содержать код, который мы хотим протестировать. Назовите проект MyMath.
  2. В том же решении добавьте новый тестовый проект MSTest. Начиная с Visual Studio 2019 версии 16.9, название шаблона проекта MSTest изменено с Проект тестов MSTest (.NET Core) на Проект модульного теста. Назовите тестовый проект MathTests.
  3. Напишите простой метод теста, который проверяет результат, полученный для конкретных входных данных. Добавьте в класс UnitTest1 приведенный ниже код.
Читайте также:
Android studio как открыть программу

[TestMethod] public void BasicRooterTest() < // Create an instance to test: Rooter rooter = new Rooter(); // Define a test input and output value: double expectedResult = 2.0; double input = expectedResult * expectedResult; // Run the method under test: double actualResult = rooter.SquareRoot(input); // Verify the result: Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 100); >

  • Создайте тип на основе кода теста.
    1. Установите курсор на Rooter , а затем в меню лампочки выберите Создать тип «Rooter»>Создать новый тип. Быстрое действие
    2. В диалоговом окне Создать тип установите для параметра Проект значение MyMath, проект библиотеки классов, и нажмите OK. Диалоговое окно
    3. Создайте метод из кода теста. Установите курсор на SquareRoot , а затем в меню лампочки выберите Создать метод Rooter.SquareRoot.
    4. Выполните модульный тест.
      1. Чтобы открыть Обозреватель тестов, в меню Тест выберите Windows>Обозреватель тестов.
      2. В обозревателе тестов выберите Запустить все, чтобы запустить тест.
      3. Выполняется сборка решения, тест запускается и завершается ошибкой.

        Сводка теста в обозревателе тестов

      4. Выберите имя теста. Дополнительные сведения о тесте появятся на панели Сводка теста.
      5. Перейдите по верхней ссылке в разделе Трассировка стека, чтобы перейти к расположению, в котором произошел сбой теста.
      6. На данном этапе создан тест и заглушка, которые будут изменены таким образом, что тест будет успешно пройден.

        Проверка изменения кода

        1. В файле Class1.cs улучшите код SquareRoot :

        public double SquareRoot(double input) < return input / 2; >

        Обозреватель тестов с пройденным тестом

      7. В обозревателе тестов выберите Запустить все. Выполняется сборка решения, тест запускается и завершается успешно.
      8. Расширение диапазона входных данных

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

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

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

        [TestMethod] public void RooterValueRange() < // Create an instance to test. Rooter rooter = new Rooter(); // Try a range of values. for (double expected = 1e-8; expected < 1e+8; expected *= 3.2) < RooterOneValue(rooter, expected); >> private void RooterOneValue(Rooter rooter, double expectedResult) < double input = expectedResult * expectedResult; double actualResult = rooter.SquareRoot(input); Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 1000); >
        public double SquareRoot(double input) < double result = input; double previousResult = -input; while (Math.Abs(previousResult — result) >result / 1000) < previousResult = result; result = result — (result * result — input) / (2 * result); >return result; >

        Добавление тестов для исключительных случаев

        1. Добавьте новый тест для отрицательных входных значений:

        [TestMethod] public void RooterTestNegativeInput() < Rooter rooter = new Rooter(); Assert.ThrowsException(() => rooter.SquareRoot(-1)); >
        public double SquareRoot(double input) < if (input .

        Рефакторинг тестируемого кода

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

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

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

        1. Измените строку, которая вычисляет result в методе SquareRoot , следующим образом:

        public double SquareRoot(double input) < if (input double result = input; double previousResult = -input; while (Math.Abs(previousResult — result) > result / 1000) < previousResult = result; result = (result + input / result) / 2; //was: result = result — (result * result — input) / (2*result); >return result; >

        Обозреватель тестов с тремя пройденными тестами

      9. Выберите Выполнить все и убедитесь, что все тесты по-прежнему завершаются успехом.
      10. Источник: learn.microsoft.com

        Программа для тестирования (тест)

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

        Тест состоит из 10 вопросов(их число может быть любым). Вот заготовки форм:

        Form2:

        Form3:

        Form4:

        Дизайн

        За рисунок на кнопке отвечает свойство Kind. Сперва изменяете это свойство на нужное, а затем в Caption прописываете то, что будет написано на кнопке.

        Читайте также:
        Все нужные программы для ютуба

        Формы

        Размер формы выберите свой, в зависимости от длин вопросов и ответов.В BorderStyle выберите BsSingle. Так же рекомендую установить в false все свойства BorderIcons, чтобы закрытие приложения мы контролировали сами. На первой форме можно оставить в true подсвойство biMinimize. В свойстве Position выберите poDesktopCenter, чтобы форма появлялась на середине экрана.

        Свойство AutoSize в false, чтобы кусок последней буквы не отсекался(актуально для формы с приветствием,справкой и результатами, для формы с тестированием лучше это свойство оставить в true). На форме с результатами слова «Вы набрали» и «баллов» пишутся в отдельных лейблах.
        За цвет, размер и тип текста отвечает свойство Font(color, size, name). Для тестирования я использовал шрифт Verdana. Для отображения надписей на других формах-Monotype Corsiva.

        Щелкаем по нему дважды и в Caption прописываем «Справка». Для вызова обработчика события нужно щелкнуть по слову «Справка» в окне с заголовком Form2->MainMenu1 .

        Вот код для каждой из форм:

        Важно!
        Текст модуля нельзя копировать напрямую, т.к. это вызовет ошибки при компиляции(относится к обработчикам событий). Следует сперва щелкнуть, например, по кнопке, а затем вставить код:

        Пример для BitBtn1 :

        Щелкаем дважды по кнопке BitBtn1, появится:

        void __fastcall TForm3::BitBtn1Click(TObject *Sender)

        Затем между фигурными скобкам вставляем код:

        Form1->Close();
        Form2->Close();
        Form3->Close();
        Form4->Close();

        И в итоге получаем:

        void __fastcall TForm3::BitBtn1Click(TObject *Sender)
        Form1->Close();
        Form2->Close();
        Form3->Close();
        Form4->Close();
        >

        Unit1.cpp

        #include
        #pragma hdrstop

        extern int pravil_otvet;//переменная, для хранения правильного ответа к вопросу

        Form2->Label5->Caption=»Как называют манекенщицу супер-класса?»;
        Form2->Label1->Caption=»Топ-модель»;
        Form2->Label2->Caption=»Тяп-модель»;
        Form2->Label3->Caption=»Поп-модель»;
        Form2->Label4->Caption=»Ляп-модель»;
        pravil_otvet=1;//присваиваем номер правильного ответа

        #include
        #pragma hdrstop

        int s=0, i=0, pravil_otvet, nomer=0;// s- сумма правильных ответов, i- вспомогательная переменная, nomer- номер текущего вопроса

        void __fastcall TForm2::N1Click(TObject *Sender)
        Form4->Visible=true;
        >
        //—————————————————————————
        void __fastcall TForm2::BitBtn2Click(TObject *Sender)
        Form2->Visible=false;
        Form3->Visible=true;
        Form3->Label2->Caption=s;
        >
        //—————————————————————————
        void __fastcall TForm2::BitBtn1Click(TObject *Sender)
        if(RadioButton1->Checked==true)i=1;//проверяем, какой ответ был выбран
        if(RadioButton2->Checked==true)i=2;
        if(RadioButton3->Checked==true)i=3;
        if(RadioButton4->Checked==true)i=4;
        if(i==pravil_otvet)s++;//если выбранный и правильный совпадают, то увеличиваем сумму на единичку
        i=0;//обнуление требуется для корректного подсчета суммы

        RadioButton1->Checked=false;//очищаем нажатую кнопку
        RadioButton2->Checked=false;
        RadioButton3->Checked=false;
        RadioButton4->Checked=false;

        nomer++;//номер вопроса изменяется с каждым нажатием кнопки

        switch(nomer)
        case 1:
        Form2->Label5->Caption=»Кто вырос в джунглях среди диких зверей?»;
        Form2->Label1->Caption=»Колобок»;
        Form2->Label2->Caption=»Маугли»;
        Form2->Label3->Caption=»Бэтмен»;
        Form2->Label4->Caption=»Чарльз Дарвин»;
        pravil_otvet=2;
        break;

        case 2:
        Form2->Label5->Caption=»Как называлась детская развлекательная программа, популярная в прошлые годы?»;
        Form2->Label1->Caption=»АБВГДейка»;
        Form2->Label2->Caption=»ЁКЛМНейка»;
        Form2->Label3->Caption=»ЁПРСТейка»;
        Form2->Label4->Caption=»ЕЖЗИКейка»;
        pravil_otvet=1;
        break;

        case 3:
        Form2->Label5->Caption=»Как звали невесту Эдмона Дантеса, будущего графа Монте-Кристо? «;
        Form2->Label1->Caption=»Мерседес»;
        Form2->Label2->Caption=»Тойота»;
        Form2->Label3->Caption=»Хонда»;
        Form2->Label4->Caption=»Лада»;
        pravil_otvet=1;
        break;

        case 4:
        Form2->Label5->Caption=»Какой цвет получается при смешении синего и красного?»;
        Form2->Label1->Caption=»Коричневый»;
        Form2->Label2->Caption=»Фиолетовый»;
        Form2->Label3->Caption=»Зелёный»;
        Form2->Label4->Caption=»Голубой»;
        pravil_otvet=2;
        break;

        case 5:
        Form2->Label5->Caption=»Из какого мяса традиционно готовится начинка для чебуреков?»;
        Form2->Label1->Caption=»Баранина»;
        Form2->Label2->Caption=»Свинина»;
        Form2->Label3->Caption=»Телятина»;
        Form2->Label4->Caption=»Конина»;
        pravil_otvet=1;
        break;

        case 6:
        Form2->Label5->Caption=»Какой народ придумал танец чардаш?»;
        Form2->Label1->Caption=»Венгры»;
        Form2->Label2->Caption=»Румыны»;
        Form2->Label3->Caption=»Чехи»;
        Form2->Label4->Caption=»Молдаване»;
        pravil_otvet=1;
        break;

        case 7:
        Form2->Label5->Caption=»Изучение соединений какого элемента является основой органической химии?»;
        Form2->Label1->Caption=»Кислород»;
        Form2->Label2->Caption=»Углерод»;
        Form2->Label3->Caption=»Азот»;
        Form2->Label4->Caption=»Кремний»;
        pravil_otvet=2;
        break;

        case 8:
        Form2->Label5->Caption=»Кто открыл тайну трёх карт графине из «Пиковой дамы» А. С. Пушкина?»;
        Form2->Label1->Caption=»Казанова»;
        Form2->Label2->Caption=»Калиостро»;
        Form2->Label3->Caption=»Сен-Жермен»;
        Form2->Label4->Caption=»Томас Воган»;
        pravil_otvet=3;
        break;

        case 9:
        Form2->Label5->Caption=»В какой стране была пробурена первая промышленная нефтяная скважина?»;
        Form2->Label1->Caption=»Кувейт»;
        Form2->Label2->Caption=»Иран»;
        Form2->Label3->Caption=»Ирак»;
        Form2->Label4->Caption=»Азербайджан»;
        pravil_otvet=4;
        break;

        case 10:
        BitBtn1->Enabled=false;
        RadioButton1->Enabled=false;//делаем кнопки «не нажимаемыми», чтобы пользователь нажал на «закончить тест»
        RadioButton2->Enabled=false;
        RadioButton3->Enabled=false;
        RadioButton4->Enabled=false;
        >
        >
        //—————————————————————————

        #include
        #pragma hdrstop

        #include
        #pragma hdrstop

        void __fastcall TForm4::BitBtn1Click(TObject *Sender)
        Form4->Visible=false;//скрываем форму справки после просмотра
        >
        //—————————————————————————

        Программа в процессе работе:

        Если вам требуется вместе с вопросом показать изображение, то используйте компонент Image и его свойство Picture. Разместите на форме нужно количество этих компонентов и в каждый подгрузите нужную картинку. Для всех свойство Visible установите в false. Затем в нужном вопросе допишите код, например:

        Form2->Label5->Caption=»Как звали невесту Эдмона Дантеса, будущего графа Монте-Кристо? «;
        Form2->Label1->Caption=»Мерседес»;
        Form2->Label2->Caption=»Тойота»;
        Form2->Label3->Caption=»Хонда»;
        Form2->Label4->Caption=»Лада»;
        Form2->Image1->Visible=true;
        pravil_otvet=1;
        break;

        Т.е. вы покажете изображение подгруженное в Image1. Но чтобы при переходе к следующему вопросу изображение убралось или заменилось новым, перед switch нужно дописать:

        Form2->Image1->Visible=false;
        Form2->Image2->Visible= false ;

        Form2->Image[i]->Visible= false ;

        В зависимости от количества ваших изображений. Это простой способ и поможет избежать отображения сразу двух изображений. Как вариант-дописать в следующем вопросе:

        case 3:
        Form2->Label5->Caption=»Как звали невесту Эдмона Дантеса, будущего графа Монте-Кристо? «;
        Form2->Label1->Caption=»Мерседес»;
        Form2->Label2->Caption=»Тойота»;
        Form2->Label3->Caption=»Хонда»;
        Form2->Label4->Caption=»Лада»;
        Form2->Image1->Visible=true;
        pravil_otvet=1;
        break;

        case 4:
        Form2->Image1->Visible= false ; //скрываем
        Form2->Label5->Caption=»Какой цвет получается при смешении синего и красного?»;
        Form2->Label1->Caption=»Коричневый»;
        Form2->Label2->Caption=»Фиолетовый»;
        Form2->Label3->Caption=»Зелёный»;
        Form2->Label4->Caption=»Голубой»;
        Form2->Image2->Visible=true; //успешно скрыв старое изображение, показываем новое
        pravil_otvet=2;
        break;

        Источник: h-l-l.ru

        Рейтинг
        ( Пока оценок нет )
        Загрузка ...
        EFT-Soft.ru