Страницы

Поиск по вопросам

Показаны сообщения с ярлыком тестирование. Показать все сообщения
Показаны сообщения с ярлыком тестирование. Показать все сообщения

среда, 15 апреля 2020 г.

Процент покрытия кода юнит-тестами

#c_sharp #net #тестирование #юнит_тесты

                    
Есть ли какой нибудь способ точно оценить процент кода, покрытого юнит-тестами (nunit)?    


Ответы

Ответ 1



Для тестов в Visual Studio есть встроенные средства, позволяющие считать покрытие. Нужно Включить расчет покрытия: Test > Edit Test Run Configurations > Your Test Configuration, далее Code Coverage, и выбрать сборку для тестирования. Прогнать тесты. Правый клик по тестам, и вызов Code Coverage Results. В итоге вы увидите статистику по процентам Not Covered Blocks Not Covered Blocks % Covered Blocks Covered Blocks % Не проверял, как это соотносится с nUnit. Еще есть сторонние стредства, например, nCover, partCover, openCover.

пятница, 13 марта 2020 г.

Как вы истрактовали бы постановку тестовой задачи?

#java #юнит_тесты #тестирование #junit


Имеется тестовое задание:


  Дан файл вида

operand1;operand2;operation;result
operand1;operand2;operation;result
operand1;operand2;operation;result
operand1;operand2;operation;result

  
  
  
  Каждая строка описывает арифметическое действие. 
  
  
  operand1 и operand2 - операнды, целые числа 
  operation - арифметическое действие + - / * 
  result - результат операции operation над operand1 и operand2
  
  
  В файле могут содержаться любые значения полей
  
  
  
  Требуется
  
  
  Реализовать юнит (JUnit) тесты арифметических действий.
  Каждое действие должно выглядеть в отчете как отдельный тестовый сценарий
  
  
  Конец задания
  
  


Я понимаю, как написать тесты JUnit, но не понимаю, что именно тестируется в данном
случае.

Правильно ли я считаю, что нужно сначала написать код, который парсит переменные,
4 функции для разных арифметических действий, а потом проверять с помощью JUnit корректность
работы функций на основании тестовых равенств в файле 
?

Прошу вас высказать свое понимание задачи.
    


Ответы

Ответ 1



Я бы написал скрипт (хотя, если там несколько строк, то можно и ручками), который на основании исходного файла нагенерирует Java файл с тестами. То есть, на каждую строку исходного файла будет генерировать что то вида @Test public void test1() { int actual = operand1 operationoperand2; int expect = result; assertEquals(expect , actual); } ну м конечно несколько строк "обвязки" для всего этого, что бы модуль был "компилируемый". В более навороченном виде я бы добалял проверку на 0 для operand2 если operation равно /. UPD Вот на коленке на perl сделать за минут 5, для собеседования считаю самое оно #!/usr/bin/perl use strict; use warnings; print ' import junit.framework.*; public class JavaTest extends TestCase { protected void setUp(){ } '; my $i = 1; while (my $line = <>) { chomp $line; my ($op1, $op2, $oper, $result) = split /;/, $line; print <<"ONE_TEST"; \@Test public void test$i() { int actual = $op1 $oper $op2; int expect = $result; assertEquals(expect, actual); } ONE_TEST $i += 1; } print "}\n";

Ответ 2



Я бы сделал 4 теста по 1 на каждую операцию (+ - / *) Каждый тест бы выбирал из файла строки со своими операциями и проверял правильность результата. Но конечно задача очень странная.

вторник, 25 февраля 2020 г.

Тест на случайность Кнута (критерий сериальной корреляции)

#c #тестирование


Добрый день! Мне нужно реализовать один из тестов Кнута. Выбрала критерий сериальной
корреляции. Во втором томе Кнута дается формула 



Я пытаюсь по ней вычислить этот коэффициент корреляции и он у меня получается при
N=50 равный 1,04. Но он не может быть, по модулю, больше единицы!... Помогите, пожалуйста,
разобраться...



Кусочек кода:

const int M=N;
unsigned int null_num, first_num, numerator_n, numerator_2, denominator_n, denominator_2;
long double C;
null_num = (a*x+c)%4294967296;
numerator_n=0;
numerator_2 = null_num;
denominator_n = null_num*null_num;

for (i=0; i


Ответы

Ответ 1



Ваш тест неверно реализован. Делайте что-то такое: double sumUV = 0, sumU = 0, sumV = 0, sumU2 = 0, sum V2 = 0; for (int i = 0; i < n; i++) { double u = GetNextU(i); double v = GetNextV(i); sumU += u; sumV += v; sumU2 += u*u; sumV2 += v*v; sumUV += u*v; } double coeff = (n * sumUV - sumU * sumV) / sqrt((n * sumU2 - sumU * sumU) * (n * sumV2 - sumV * sumV)); Это, к сожалению, достаточно наивный код: из-за неточности при округлении результат может оказаться катастрофически неточен. О подробностях читайте в Кнуте, 4.2.2. Пример после формулы (15) показывает, что при вычислении корня в знаменателе вы можете столкнуться с отрицательным числом, несмотря на то, что это математически невозможно. Апдейт. С новой формулой у вас V_i = U_{i+1}, вы считаете корреляцию последовательности на себя. Код можно упростить. double sumU = 0, sumU2 = 0, sumUShifted = 0; double firstU = GetNextU(0); double prevU = firstU; for (int i = 0; i < n; i++) { double nextU = i == (n - 1) ? firstU : GetNextU(i + 1); sumU += prevU; sumU2 += prevU*prevU; sumUShifted += prevU*nextU; prevU = nextU; } double coeff = (n * sumUShifted - sumU * sumU) / (n * sumU2 - sumU * sumU);

понедельник, 24 февраля 2020 г.

Тестирование и избавление от связности классов.

#c_sharp #aspnet #aspnet_mvc #юнит_тесты #тестирование


Добрый день! У меня есть приложение asp.net mvc. В нем я пытаюсь создавать архитектуру
"по уму" - с Dependency Injection, тестами и тд. В приложении есть классы-сервис, в
которых сосредоточена бизнес-логика. Мне необходимо покрыть эти сервисы тестами. Многие
сервисы используют класс настроек, экземпляры которых им передаются в конструкторах.
Например: 

public class AppSettings  
{
    public AppSettings()
    {
        SomeStr =  WebConfigurationManager.AppSettings["str"]).ToString();  
        // и еще несколько подобных  строк         
    }

    public string SomeStr { get;set; }
}


public class MyService 
{
    public MyService(AppSettings settings)
    {
        _settings = settings;
    }

    private readonly AppSettings _settings;
}


Проблема тут вот какая. В конструкторе класса AppSettings происходит инициализация
неких переменных, данные о которых получаются из файла web.config. В коде самого приложения
это работает, а вот если я пытаюсь тестировать класс MyService в отдельном тестовом
приложении, то возникает проблема: классу нужно передавать экземпляр AppSettings, но
при его создании  вываливается исключение из-за невозможности обратиться к web.config.
Кроме того сами классы я напрямую не создаю, этим занимается DI-библиотека. Как быть
в данном случае и как нормально протестировать MyService? К тому же мне кажется проблемой
то, что в конструкторе класса AppSettings происходит обращение к `web.config. Подскажите
пожалуйста как решить эту проблему? Заранее благодарю.
    


Ответы

Ответ 1



Если вы используете класс AppSettings как класс настроек и IoC-контейнер, то опишите интерфейс IAppSettings и протестируйте с помощью Mock объектов. Приведу пример. В классе MyService вы заменяете тип аргумента конструктора settings на IAppSetting. В IoC-контейнере регистрируете реализацию. Предположим, что вы используете Ninject, тогда kernel.Bind().To(). Тогда в методе тестирования вы можете настроить свой объект. Mock() mock = new Mock(); mock.Setup(m => m.Field1).Returns(value1); MyService service = new MyService(mock.Object); Здесь вы задаете, что при запрашивании Field1 должно вернуться значение value1. Внимание поле Field1 должно быть определено в интерфейсе IAppSetting Пример показан для Ninject

воскресенье, 16 февраля 2020 г.

Тестирование и избавление от связности классов.

#c_sharp #aspnet #aspnet_mvc #юнит_тесты #тестирование


Добрый день! У меня есть приложение asp.net mvc. В нем я пытаюсь создавать архитектуру
"по уму" - с Dependency Injection, тестами и тд. В приложении есть классы-сервис, в
которых сосредоточена бизнес-логика. Мне необходимо покрыть эти сервисы тестами. Многие
сервисы используют класс настроек, экземпляры которых им передаются в конструкторах.
Например: 

public class AppSettings  
{
    public AppSettings()
    {
        SomeStr =  WebConfigurationManager.AppSettings["str"]).ToString();  
        // и еще несколько подобных  строк         
    }

    public string SomeStr { get;set; }
}


public class MyService 
{
    public MyService(AppSettings settings)
    {
        _settings = settings;
    }

    private readonly AppSettings _settings;
}


Проблема тут вот какая. В конструкторе класса AppSettings происходит инициализация
неких переменных, данные о которых получаются из файла web.config. В коде самого приложения
это работает, а вот если я пытаюсь тестировать класс MyService в отдельном тестовом
приложении, то возникает проблема: классу нужно передавать экземпляр AppSettings, но
при его создании  вываливается исключение из-за невозможности обратиться к web.config.
Кроме того сами классы я напрямую не создаю, этим занимается DI-библиотека. Как быть
в данном случае и как нормально протестировать MyService? К тому же мне кажется проблемой
то, что в конструкторе класса AppSettings происходит обращение к `web.config. Подскажите
пожалуйста как решить эту проблему? Заранее благодарю.
    


Ответы

Ответ 1



Если вы используете класс AppSettings как класс настроек и IoC-контейнер, то опишите интерфейс IAppSettings и протестируйте с помощью Mock объектов. Приведу пример. В классе MyService вы заменяете тип аргумента конструктора settings на IAppSetting. В IoC-контейнере регистрируете реализацию. Предположим, что вы используете Ninject, тогда kernel.Bind().To(). Тогда в методе тестирования вы можете настроить свой объект. Mock() mock = new Mock(); mock.Setup(m => m.Field1).Returns(value1); MyService service = new MyService(mock.Object); Здесь вы задаете, что при запрашивании Field1 должно вернуться значение value1. Внимание поле Field1 должно быть определено в интерфейсе IAppSetting Пример показан для Ninject

воскресенье, 9 февраля 2020 г.

Мокинг статических методов. Когда это нужно делать?

#c_sharp #юнит_тесты #тестирование #статические_члены


Ранее как-то особо не обращал внимание на статические методы и сейчас когда вижу,
что для некоторых (иногда даже кажется что для большинства) мне не нужно задавать/хранить
состояние, то решил сделать их статическими. Но становиться вопрос, что тогда на счет
мокинга этих методов в классах, где они являются зависимостями, ведь в интерфейсе нельзя
объявить статический метод и соответственно другую реализацию подсунуть становить затруднительно
стандартными средствами.

Например, есть код

public class Hasher
{
    public static void RenameByHash(string filePath)
    {
        //...
    }
}

public class MyService
{
    public void ProccessPres(string presentationPath)
    {
        //...

        Hasher.RenameByHash(presentationPath);

        //...
    }
}


Я ведь теперь при тестировании метода ProccessPres() не могу замокать Hasher.RenameByHash().
И прихожу к тому, что приходиться вообще отказаться от статических методов, т.к. не
могу изолировать их поведение и тестировать только свой сервис.

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

Фреймворки для мокинга статических методов. Также есть статья в которой говорится,
что для мокинга статических методов можно использовать более навороченные мокинг-фреймворки
типа Typemock, JustMock, Moles. Но насколько нужно это мне, как я писал выше, было
бы ясно если я убедился бы в том, что правильно понимаю теоретическую основу статических
методов касательно их имитации. Быть может мокать поведение статические методов в большинстве
случаев и вовсе не нужно как не нужно мокать приватные методы.
    


Ответы

Ответ 1



Имхо, статические методы должны 1) Делать очень маленькую специфичную работу 2) Не должны напрямую относиться к бизнес логике 3) Как следствие 1) и 2) - их не надо мокать 4) Их можно тестировать отдельно По большому счету они очень похожи на расширяющие методы. Например, string.IsNullOrEmpty(...) DateTime.ConvertToLocalTIme(...) Но если у вас есть какой то бизнес класс, который не обладает состоянием (например, какой то сервис отсылки сообщений или калькулятор стоимости товара или что то подобное), то есть смысл делать его синглтоном, то есть иметь только 1 экземпляр такого сервиса на всё приложение/домен/подсистему и тд. Я предпочитаю делать синглтоны за счет инверсии зависимости. То есть класс сам не знает, что он синглтон - это указывается в корне композиции при регистрации типов в IoC контейнере или вручную. Таким образом, классы без состояния можно тестировать как любые другие классы. UPD На самом деле, если заходить дальше, то ваши подсистемы по идее должны взаимодействовать посредством контрактов (это такая общая рекомендация), что обычно означает интерфейсов. Грубо говоря, при использовании IoC весь необходимый для класса воспомогательный бизнес функционал должен быть инжектирован через конструтор, свойство или каким либо другоим методом (я почти всегда выбираю конструктор). То есть используюя какой то бизнес функционал, ваш класс должен вызвать метод какого либо инстанса (ведь вы не можете инжектировать статический класс/метод). Таким образом мы приходим к тому, что вызов статического метода стороннего класса идет в разрез с принципом инверсии зависимости. С другой стороны, преобразование обычного класса (или его пубичного метода) в статический увеличивает связность классов, так как интерфейсы не содерджат статических методов, а значит вызвать статический класс/метод вы можете только явно. То есть делая класс или его публичный метод статическим, вы уменьшаете гибкость системы вцелом. Потому есть смысл это делать только в тех случаях, когда у таких классов/методов в приципе возможна только одна имплементация, которая не содержит состояния и которую вы точно не захотите менять никогда (string.IsNullOrEmpty четко дает понять, что происходит внутри метода и другой реализации этого метода быть не может) - то есть в таких случаях вы жертвуете гибкостью там, где она в принципе не нужна. Во всех остальных случаях я стараюсь избегать модификатора static вообще. Что же касается внутренней реализации класса - приватных статических членов, это уже другой разговор, тут уже можно делать статическим все, что удобно, так как это внутренняя кухня класса (особенно если от этого класса запрещено наследование).

пятница, 31 января 2020 г.

Тестирование в Java

#java #тестирование


Начнём с того, что я новичок, пользуюсь IDEA. Интересуюсь, как разработкой оффлайн
приложений, так и web-, даже про Android был бы не против, что-нибудь услышать, хотя
и меньше, чем про первые два варианта. Напишу сначала, что я знаю о тестировании:
1) В некоторых книгах (и не только) рекомендуется такой подход к программированию,
при котором перед тем, как писать непосредственно код, пишутся тесты. Если я правильно
понял, тесты пишутся ко ВСЕМ классам, которые будут в коде. Но во первых, написание
теста к классу требует такого же времени, что и написание самого класса, а иногда и
гораздо большего. Во вторых, в тех ситуация, которые я учёл, класс будет функционировать
исправно (за исключением опечаток), а в тех ситуациях, которые я не учёл, тест будет
проходится успешно (т.к. они не заложены в тест). И в третьих, иногда не знаешь как
будет выглядеть некий класс, до тех пор, пока его не реализуешь, более того, и после
реализации будет много раз видоизменятся, иногда кардинальным образом - например: попробовал
один подход - скорость отработки низкая, попробовал совершенно другой (с другим набором
классов и интерфейсов) - выше. 

Так вот стоит ли прибегать к такому подходу? И как быть с учётом всего, выше написанного?
Меня как-то панический страх берёт писать тесты все геттеры/сеттеры...

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

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

3) Может я ещё что-то упустил в области тестирования... Буду рад любым наставлениям
;)    


Ответы

Ответ 1



есты пишутся ко ВСЕМ классам писать тесты абсолютно на все - не самая здравая идея. в тех ситуация, которые я учёл, класс будет функционировать исправно не факт. У вас же нет никакой гарантии, что вы правильно реализовали "то, что учли". Проверить это как раз помогут тесты в тех ситуациях, которые я не учёл, тест будет проходится успешно (т.к. они не заложены в тест) разработчик обязан знать, что должен делать тот или иной его класс, соответственно, тестировать свои классы он должен на предмет соответствия этому "предназначению". Следовательно, описанная вами ситуация не имеет смысла иногда не знаешь как будет выглядеть некий класс, до тех пор, пока его не реализуешь см. выше - разработчик должен знать, что будет делать создаваемый им класс, и тестировать его именно с этой точки зрения. Следовательно, тестированию не особо интересны детали реализации этого класса (и возможные изменения в этой реализации) И наконец, не сочтите за занудство, но выглядит ужасно: не "координальным", а кардинальным, и не "просвятите", а просветите

Ответ 2



Важна мера во всем. Тестируются обычно сложные случаи. А так вообще все тестировать никаких сил не хватит. Потом ведь надо будет писать тесты тестов (я серьезно). К тому же тестирование бывает разным: юнит тесты, нагрузочное тестирование, функциональное тестирование и т.д. Не зря среди прогерской братии есть специальность тестировщик/тестер. Прогер должен тестировать конечный результат своего труда. Скажем написали некий класс/иерархию выполняющую допустим скачивание контента из сети. Логичным было бы написать юнит тест проверяющий идентичность скачанного со скачиваемым. В общем идея проста: Вам мудрое руководство поставило некую задачу; Вы ее решили; Теперь надо доказать, что решение работает. Для этого пишете юнит тест (серию юнит тестов) доказывающих работоспособность вашего решения; Показываете руководителю; Профит. P.S. Касательно бинов. Если вам поставили задачу написать бины - значит придется писать юнит тесты на ваши бины. Такова се ля ви :)

Ответ 3



Вот хороший плагин для Eclipse, который определяет уровень, насколько ваш код покрыт тестами. http://eclemma.org/

Как в Android Studio тестировать участок кода на время прохождения?

#java #android #тестирование


Как в Android Studio тестировать определенный участок кода на время прохождения?

Всё что мне необходимо — это получить данные и показать.
    


Ответы

Ответ 1



Лучше позже чем никогда. Вопрос довольно простой на первый взгляд, и решить его можно разными способами. После прочтения ряда статей, тестов с разных источников, в основном официальных, я решил эту проблему следующим путем: Покрывал я участки кода JUnitPerf у него есть парочка оболочек на время прохождения, в случае отклонение, выводим что необходимо. И это, то что я искал. Но вопрос был сформулирован по другому, для этого я эмулировал несколько ситуаций и сделал свой тест: вначале я использовал разные БД(было интересно), позже я упростил и использовал различные интерфейсы коллекций и записывал и удалял небольшое кол-во записей, а точней 100.000, как оказалось позже это очень удачное число, но не суть. Я уже знал, что в корне необходимо использовать два нативных метода системы, но мы вернемся немного назад, почему так измерять нельзя?: DateFormat.getDateTimeInstance().format(new Date()) Я думаю многие знают или догадываются, но вкратце - много здесь ненужных действий начиная стилей даты, создание объекта, потом нам необходимо как-то измерять точку входа и выхода - autoboxing etc, всё это создаст огромную погрешность, и в итоге сильный разброс при замере одной и той же операции. Но если даже всё убрать и сделать так: Date date = new Date(); Даже так плохо, мы тратим время на создание объекта класса, и его внутреннюю реализацию, смотрим внутрь и видим public Date() { this(System.currentTimeMillis()); } Нас это больше чем устраивает, чтоб не плодить экземпляры класса. Это и есть один из методов, второй рядышком давайте их запишем вместе, через вызов, чтоб было удобней читать: System.currentTimeMillis(); System.nanoTime(); Возвращает long, второй более точный(подробный), в наносекундах. Читаем оф документацию и видим в nanoTime(): This timestamp should only be used to measure a duration by comparing it against another timestamp on the same device. Есть нюансы, но суть в оф документации там всё очевидно: nanoTime и рядом currentTimeMillis После этого можно окончить, но вернемся к тесту. Много информации о том, что погрешность может исчисляться 10-15мс в зависимости от ситуаций(напомню между двумя этими подходами), я хотел бы это опровергнуть, но.... я сделал огромное кол-во пусков теста с различными параметрами с разными устройствами, я учитывал множество факторов, значения записывал только после выделения памяти, учитывал номер записи у меня был алгоритм подсчета среднего значения и ещё оооочень большое кол-во нюансов, и самый сильный разброс был таков: System.nanoTime(); //374-412мс System.currentTimeMillis(); //386-439мс Это индивидуальный случай, и скорей всего ошибки в замерах, но это факт. Возможно если увеличить кол-во записей в N кол-во всё и свелось бы к min, но я написал, что это был самый сильный разброс. В среднем как раз и было 10-15мс, но иногда иногда как в примере выше был другой рез-т. В итоге ответ: long startTime = System.nanoTime(); // ... the code being measured ... long estimatedTime = System.nanoTime() - startTime; Самый точный способ замера участка кода, на одном устр-ве из тех которые я нашел.

Ответ 2



Например можно сделать вывод в лог текущего времени в начале и в конце тестируемого кода и посмотреть на разницу: Log.d("Log", DateFormat.getDateTimeInstance().format(new Date()));

пятница, 24 января 2020 г.

Затруднения в алгоритме формирования таблиц истинности

#c_sharp #тестирование


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


Сигнал – это базовая единица. Может существовать как самостоятельно, так и в логике
формирования параметра (будет рассмотрен ниже). Тип сигнала может быть следующим –
int, real, bool(на данном этапе написания приложения реализую только этот тип сигнала),
enum и range (Например сигнал может быть типа int, однако валидными для него значения
будут [0..4])
Параметр – это составная единица логики. Имеет внутреннюю логику формирования. Может
формироваться только из сигналов, либо из сигналов и других параметров. Тип параметра
может быть как bool, так и любой числовой. Также параметр может формироваться с помощью
блоков if/then/else. Например 

A = if(B)then(true)
      Else (if (C) then (true) Else (false))
ВАЖНО: в логике формирования одного параметра могут принимать участие несколько одинаковых
сигналов. Например : A = (B|C)&(B|D), где A – это параметр, а B, C, D – это сигналы
типа bool. Также, в логике формирования нескольких параметров могут принимать участие
несколько одинаковых сигналов. Например A = (B|C), E = (B|D), F = (A&B), где A,E,F
– параметры, а B,C,D – сигналы типа bool.


Итак, перейдём к элементарным примерам ожидаемой работы приложения.
1)  Допустим, есть следующая логика формирования параметра A «A = (B&C)», где B и
С – это сигналы типа bool. Данный выход является базовым, для операции “&”. На выходе
приложение должно выдать следующую таблицу(матрицу состояний) : 
 
2)  Допустим, есть следующая логика формирования параметра A «A = (B|C)», где B и
С – это сигналы типа bool. Данный выход является базовым, для операции “|”. На выходе
приложение должно выдать следующую таблицу(матрицу состояний) :

3)  Допустим, есть следующая логика формирования параметра A «A = (B&C)|D», где B,
C и D – это сигналы типа bool. В данном примере синей границей выделена ситуация для
«&», а красной для «|». Стоит отметить, что для ситуации с «|» показано 2 случая, поскольку
случай, когда D = false, а (B&D) = true показан в первой строке примера для оператора
«&». На выходе приложение должно выдать следующую таблицу(матрицу состояний) :


Исходя из вышеописанного, у меня возникло к Вам несколько просьб о помощи с реализацией:  

1)  Подскажите, как можно реализовать приоритет выполнения операций?  

2)  Каким образом мне лучше строить таблицу для логики формирования основного (родительского)
параметра? Есть ли соображения как элегантно реализовать данный алгоритм?  

3)  Как реализовать логику для блоков if/then/else

Собственно, мои начальные наброски приложения Вы можете найти в https://github.com/RusProgrammer/Logica

Буду рад любой помощи с Вашей стороны и заранее Вам благодарен.
    


Ответы

Ответ 1



Предположим, наша задача сводится к построению минимальной не противоречивой таблицы истинности для некоторого логического выражения. Тогда есть два варианта варианта получить такую минимальную таблицу: Строить таблицу в которой указаны наборы входных значений для получения истинного результата, остальные приводят к ложному (у нас же бинарная логика?) Строить таблицу в которой указаны наборы входных значений для получения ложного результата, остальные приводят к истинному. В обоих случаях мы получаем такую таблицу истинности, по которой можно восстановить исходную функцию для которой она была получена. Вспомним немного теории. В бинарной логике существует 16 различных функций от 2х аргументов. Из них три две and и or дополненные унарным отрицанием not образуют базис, т.е. такой набор функций, с помощью которого можно составить выражение определяющее любую из 16 возможных функций. Из этого утверждения следует, что любое, сколь угодно сложное, выражение от произвольного числа аргументов может быть записано с использованием только этих трех функций. Полагаю что это и так известно, но люди заглядывают разные, пусть тоже будет. Доказательство легко гуглится в той же вики и рассказывается чуть ли не на первом курсе любого технического вуза. Приоритет операций: not, and, or в порядке убывания, по аналогии с математическими -(унарный), *, + Для удобства, сложные функции приводят сначала к виду КНФ/ДНФ а затем к виду СКНФ/СДНФ (гуглим прямо по аббревиатуре, первой же ссылкой будет статья на вики) Теперь рассмотрим несколько простых функций и минимальные таблицы истинности для них, для определенности считаем что мы ищем истинные результаты. And x1 x2 | y 1 1 | 1 y = x1 & x2 (КНФ и СКНФ совпадают) остальные наборы приводят к 0 и приводить их не требуется Or x1 x2 | y 1 1 | 1 1 0 | 1 0 1 | 1 y = x1 | x2 (КНФ)= x1&x2 | x1&~x2 | ~x1&x2 (СКНФ) XOR x1 x2 | y 1 0 | 1 0 1 | 1 y = x1&~x2 | ~x1&x2 (КНФ и СКНФ совпадают) Думаю принцип понятен. Не сложно заметить, что в виде СКНФ, знаки аргументов в выражении фактически копируют нужные строки из таблицы истинности. Теперь рассмотрим выражение из вопроса A = (B&C)|D. вобщем то оно уже представлено в форме КНФ, осталось расширить его до СКНФ и получить таблицу истинности. A = B&C | D = B&C&D | B&C&~D | ~B&~C&D B C D | A 1 1 1 | 1 1 1 0 | 1 0 0 1 | 1 Ок. Допустим теперь нам нужно добавить зависимость от аргумента E так, что в результате получается выражение A = ((B&C)|D)&E. Не сложно заметить, что оно использует в качестве аргумента предыдущее выражение. Тогда можно воспользоваться предыдущим результатом: A = (B&C | D)&E = (B&C&D | B&C&~D | ~B&~C&D) & E = B&C&D&E | B&C&~D&E | ~B&~C&D&E B C D E | A 1 1 1 1 | 1 1 1 0 1 | 1 0 0 1 1 | 1 Те же 3 строки, ну уже с учетом дополнительного параметра. В общем то добавление новых параметров к имеющимся не составляет труда. В случае объединения двух выражений ровно то же самое. Правила бинарной алгебры логики можно посмотреть тут, в принципе они не сильно отличаются от правил арифметических преобразований, но некоторые существенные отличия все таки есть, так что повторить не повредит, даже если уже их знаете. Теперь как это применить для программирования этой самой логики. С одной стороны, мы задаем формулу, анализируем ее, преобразуем к нужному виду и формируем таблицу. Не слишком сложно, но если проект инженерный, я бы пошел от обратного. Строим таблицу истинности нашего абстрактного вычислителя и кладем ее в массив. Эта таблица и будет программой для нашего вычислителя. Теперь когда нам потребуется выполнить операцию, мы проходим по строкам таблицы истинности и объединяем все элементы строки операцией and, если элемент в строке равен 0, предварительно инвертируем (применяем отрицание) соответствующий входной сигнал. Затем объединяем результаты строк операцией or и отдаем результат пользователю. Если входной набор удовлетворяет одной из строк таблицы, на выходе будет истина, в противном случае ложь. Таким образом мы можем получить некий абстрактный вычислитель, программируемый с помощью таблицы истинности. Разумеется, такое решение уступает по производительности варианту с намертво вкомпилированной в код логикой, однако при этом позволяет менять логику на ходу, за это и платим производительностью. Для варианта с большим количеством входов и выходов и выходов, можно применить более хитрый прием. Задать целыми числами массив пар: состояние входов => состояние выходов, также определить какое состояние выходов должно быть, если ни состояние входов не совпадает ни с одним из заданных. Дальше просто - из входных сигналов формируем последовательность бит числа, и, уже в виде числа, сравниваем с заданными состояниями, нашли - возвращаем заданные ответ, не нашли, возвращаем предусмотренное на этот случай значение. Ответ можно возвращать как числом, так и массивом bool-значений, разобрать число на биты не сложно. 1) Подскажите, как можно реализовать приоритет выполнения операций? Посмотрите алгоритм перевода обычного инфиксного выражения в обратную польскую запись, там хорошо видно как учитываются приоритеты, к тому же этот алгоритм с минимальными переделками позволяет вычислять выражения любой сложности. 2) Каким образом мне лучше строить таблицу для логики формирования основного (родительского) параметра? Есть ли соображения как элегантно реализовать данный алгоритм? выше я написал что есть 2 пути, анализ знаков аргументов в выражении приведенном к СКНФ/СДНФ виду, либо идти в обратную сторону, и вместо вычисления таблицы истинности, выводить формулу по заданной таблице. Второе проще и в реализации и для конечного пользователя, т.к. ему не нужно будет вспоминать нюансы алгебры логики для получения корректного выражения. 3) Как реализовать логику для блоков if/then/else Не понял причем ту это, но по идее можно реализовать как тернарный оператор ? : с соответствующей обработкой. Пример построения таблицы по выражению приведу на примере последнего выражения: var ResultTable = new List>(); var expr = "B&C&D&E|B&C&~D&E|~B&~C&D&E";//выражение в СКНФ-форме var lines = expr.Split('|'); for(int i = 0; i < lines.Length; i++) { ResultTable.Add(new List); var args = line[i].Split('&'); for(int j = 0; j < args.Length; j++) { table[i].Add(args[j][0] != '~'); } } Получим список строк, содержащих значения аргументов, в зависимости от наличия инверсии перед аргументом. Значения функции можно не вводить, т.к. известно, что СКНФ строится для истинных значений функции (СДНФ - для ложных). Это один из возможных путей реализации и далеко не единственный. Небольшое замечание, иногда имеет смысл предварительно оценить количество возможных истинных и ложных состояний и выбрать СКНФ или СДНФ представление в зависимости от того, каких значений меньше. Это может быть критично для функций с большим числом аргументов, т.к. суммарное число возможных входных наборов 2^n, где n-число аргументов в выражении, и если из них всего несколько приводит к истинному результату - выбираем СКНФ, если несколько ложных, остальные истинные - выбираем СДНФ. Так мы всегда будем получать таблицы с числом строк меньше либо равным (2^n)/2. Если что забыл, пишите в комментариях, дополню.

Кодревью: модульные тесты для простых доменных объектов

#c_sharp #инспекция_кода #тестирование


И снова я с темой инспекции кода, почитав книги по модульному тестированию.

Проект .NetFramework 4.6.1, фреймворк тестирования - nUnit.

У меня есть два простых класса в доменной модели: Order и OrderPosition:

Заказ:

using System;
using System.Collections.Generic;
using System.Linq;

namespace MyCompanyName.MyProjectName.Domain
{
    public class Order
    {
        public Order(int id, DateTime created, IList orderPositions)
        {
            this.Id = id;
            this.Created = created;
            this.OrderPositions = orderPositions;
        }

        public int Id { get; }

        public DateTime Created { get; }

        public ICollection OrderPositions { get; }

        public int PositionsCount
        {
            get { return this.OrderPositions.Count; }
        }

        public decimal OrderPrice
        {
            get { return this.OrderPositions.Sum(x => x.TotalPrice); }
        }
    }
}


Позиция заказа:

using System;

namespace MyCompanyName.MyProjectName.Domain
{
    public class OrderPosition
    {
        private int _quantity;
        private string _title;

        public OrderPosition(int id, int orderId, string title, int quantity, decimal
unitPrice, decimal discount)
        {
            this.Id = id;
            this.OrderId = orderId;
            this.Title = title;
            this.Quantity = quantity;
            this.UnitPrice = unitPrice;
            this.Discount = discount;
        }

        public int Id { get; }

        public int OrderId { get; }

        public string Title
        {
            get { return this._title; }
            private set
            {
                if (value != null && value.Length > 20)
                    throw new ArgumentException(nameof(this.Title));

                this._title = value;
            }
        }

        public int Quantity
        {
            get { return this._quantity; }
            private set
            {
                if (value < 1)
                    throw new ArgumentException(nameof(this.Quantity));

                this._quantity = value;
            }
        }

        public decimal UnitPrice { get; }

        public decimal Discount { get; }

        public decimal TotalPrice
        {
            get { return this.UnitPrice * this.Discount * this.Quantity; }
        }
    }
}


(Я несколько упростил пример из реального предложения, убрав справочник товаров,
вспомогательные поля чтобы сильно не раздувать код вопроса, но демо-приложение полностью
рабочее)

Попробовал написать юнит-тесты для этих классов. 

Предварительно замечу по соглашению о наименовании классов: я использовал реже встречающийся
вариант, когда имя тестового класса идёт по шаблону <НазваниеТестируемого класса>Test_<тестируемый
метод>.

В первую очередь я набросал несколько тестов на автосвойства без всякой логики, например
Order.Id, Order.Created, OrderPosition.UnitPrice, OrderPosition.Discount. 

Приведу лишь пару примеров, они все однотипные.

Для OrderPosition.UnitPrice такой тест:

using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderPositionTests_UnitPrice : OrderPositionTestsBase
    {
        [Test]
        public void Always_SetProp()
        {
            const decimal unitPrice = 123M;

            var result = NewOrderPosition(1, 2, "asdf", 3, unitPrice, 0.1M);

            Assert.AreEqual(unitPrice, result.UnitPrice);
        }
    }
}


Где в базовый класс вынесена логика инициализации объекта:

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    public class OrderPositionTestsBase
    {
        protected static OrderPosition NewOrderPosition(int id, int orderId, string
title, int quantity, decimal unitPrice, decimal discount)
        {
            return new OrderPosition(id, orderId, title, quantity, unitPrice, discount);
        }
    }
}


По рекомендациям Ошероува выносить инициализацию в фабричный метод.

Аналогично для Order.Id, там просто чуть больше данных конструируется:

using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderTests_Id : OrderTestsBase
    {
        [Test]
        public void Always_SetProp()
        {
            const int orderId = 1;

            var result = NewOrder(orderId, new DateTime(), new List
{ NewOrderPosition(1, orderId, "asdf", 2, 1234M, 0.1M) });

            Assert.AreEqual(orderId, result.Id);
        }
    }
}


И так же в базовый класс вынесена логика конструирования объекта:

using System;
using System.Collections.Generic;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    public class OrderTestsBase
    {
        protected static Order NewOrder(int id, DateTime created, IList
orderPositions)
        {
            return new Order(id, created, orderPositions);
        }

        protected static OrderPosition NewOrderPosition(int id, int orderId, string
title, int quantity, decimal unitPrice, decimal discount)
        {
            return new OrderPosition(id, orderId, title, quantity, unitPrice, discount);
        }
    }
}


Далее я написал тесты для свойств, содержащих какую-никакую но логику.

Для поля "количество" я проверяю, что оно не может содержать нуль или отрицательные
числа:

using System;
using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderPositionTests_Quantity : OrderPositionTestsBase
    {
        [Test]
        public void ZeroValue_ThrowsArgumentException()
        {
            const int quantity = 0;

            var ex = Assert.Throws(() => NewOrderPosition(1, 2,
"asdf", quantity, 1234M, 0.1M));

            StringAssert.Contains(nameof(OrderPosition.Quantity), ex.Message);
        }

        [Test]
        public void NegativeValue_ThrowsArgumentException()
        {
            const int quantity = -1;

            var ex = Assert.Throws(() => NewOrderPosition(1, 2,
"asdf", quantity, 1234M, 0.1M));

            StringAssert.Contains(nameof(OrderPosition.Quantity), ex.Message);
        }

        [Test]
        public void PositiveValue_SetProp()
        {
            const int quantity = 1;

            var result = NewOrderPosition(1, 2, "asdf", quantity, 1234M, 0.1M);

            Assert.AreEqual(quantity, result.Quantity);
        }
    }
}


Для строки "наименование позиции товара" я контролирую длину строки:

using System;
using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderPositionTests_Title : OrderPositionTestsBase
    {
        [Test]
        public void NullValue_IsCorrect()
        {
            const string title = null;

            var result = NewOrderPosition(1, 2, title, 2, 1234M, 0.1M);

            Assert.IsNull(result.Title);
        }

        [Test]
        public void ShortStringValue_SetsProp()
        {
            const string title = "asdf";

            var result = NewOrderPosition(1, 2, title, 2, 1234M, 0.1M);

            Assert.AreEqual(title, result.Title);
        }

        [Test]
        public void TooLongValue_ThrowsArgumentException()
        {
            const string title = "123456789012345678901";

            var ex = Assert.Throws(() => NewOrderPosition(1, 2,
title, 2, 1234M, 0.1M));

            StringAssert.Contains(nameof(OrderPosition.Title), ex.Message);
        }
    }
}


После этого у меня остались расчётные поля.

Для OrderPosition это TotalPrice:

using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderPositionTests_TotalPrice : OrderPositionTestsBase
    {
        [Test]
        public void UnitPriceDiscontinued_Always_CalculatesTotalPrice()
        {
            var orderPosition = NewOrderPosition(1, 2, "", 2, 10M, 0.1M);

            var totalPrice = orderPosition.TotalPrice;

            Assert.AreEqual(2M, totalPrice);
        }
    }
}


Для Order это PositionsCount:

using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderTests_PositionsCount : OrderTestsBase
    {
        [Test]
        public void Always_ReturnsCount()
        {
            const int orderId = 1;
            var orderPositions = new List
            {
                NewOrderPosition(1, orderId, "test", 1, 10M, 0.1M),
            };
            var order = new Order(orderId, new DateTime(), orderPositions);

            var orderPositionsCount = order.PositionsCount;

            Assert.AreEqual(orderPositions.Count, orderPositionsCount);
        }

        [Test]
        public void Always_ReturnsCount2()
        {
            const int orderId = 1;
            var orderPositions = new List
            {
                NewOrderPosition(1, orderId, "test1", 1, 10M, 0.1M),
                NewOrderPosition(2, orderId, "test2", 3, 12M, 0.2M),
            };
            var order = new Order(orderId, new DateTime(), orderPositions);

            var orderPositionsCount = order.PositionsCount;

            Assert.AreEqual(orderPositions.Count, orderPositionsCount);
        }
    }
}


и OrderPrice:

using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace MyCompanyName.MyProjectName.Domain.Tests.Unit
{
    [TestFixture]
    public class OrderTests_OrderPrice : OrderTestsBase
    {
        [Test]
        public void UnitPriceDiscontinued_Always_ReturnsDiscontinuedPrice()
        {
            const int orderId = 1;
            var order = new Order(orderId, new DateTime(), new List
{ NewOrderPosition(1, orderId, "test", 1, 10M, 0.1M) });

            var orderPrice = order.OrderPrice;

            Assert.AreEqual(1M, orderPrice);
        }
    }
}


На этом в принципе я решил подвести черту и провести ревью.

В первую очередь меня интересуют следующие вопросы:


Каких тестов не хватает?
Какие тесты нужно исключить или переделать?
Нужно ли как-то отдельно протестировать конструкторы? Если да, то как? Если нет -
то почему?
Есть ли какие-то рекомендации по наименованию тестов?
Покрывают ли тесты (особенно там где логика или расчёты) все возможные ситуации?
Какие есть замечания по самому коду тестов?


Также если есть какие-то замечания по самим тестируемым классам - тоже буду признателен
за обратную связь.
    


Ответы

Ответ 1



Громаднейший вопрос. Что касается наименования тестов, то тут использовать правильнее наименования: class Test_НаименованиеТестируемогоКласса (удобнее искать тесты при изменении класса) Что касается наименования методов тестирования тут лучше пользоваться void Test_Наименование(метода/свойства)In(Входные параметры, если нужны)Out(Что должны получить на выходе)(удобство при поиске нужного теста) При большом количестве моделей данных удобно добавить категорию перед методом:[Category("модель")]void Test_Наименование(метода/свойства)In... или даже перед классом - это дает удобство при изменении модели, у вас есть возможность выбрать все тесты связанные с конкретной моделью, такое удобно и при интеграционном тестировании В Assert.AreEqual - добавить текст ошибки, типа Assert.AreEqual(a,b,"ожидалось {0}, в результате выполнения получили {1}",a,b); - такое удобно в дальнейшем для отладки самого теста и конечно по прошествии большого времени вам этот текст поможет понять, а что вы ожидали в итоге. Иногда, чаще всего когда нужна отчетность по выполнению тестов, можно добавлять запись логов, но тут надо быть крайне осторожными, однако в этом есть свои прелести, например, можно автоматизировать отчет о проделанной работе над проектом, либо создать отчет о не прошедших тестах, и получить в одном месте причины не прохождения тестов в проекте. Однако с логгированием не стоит увлекаться, так как тесты должны быть простыми, и легко разбираемыми. Что нужно тестировать? Вопрос весьма спорный, так например я встречал в книгах, что тестировать нужно все публичные методы и свойства, однако если у вас есть просто {get;set;}, что вы тогда будете тестировать? Однако у таких свойств есть обрабочики, наподобие взять из свойства одного объекта и поставить в свойства другого, тогда этот обработчик надо тестировать. Обязательно надо тестировать свойства с внутренней логикой установки и получения на подобие: {get{...}set{...}} На счет покрытия всех ситуаций, тут весьма интересный вопрос, Вы не БОГ! поэтому предвидеть все ситуации в особо сложных случаях не сможете. Однако дополнять тесты на основе пойманных багов. вам никто не запретит, и это даже правильнее, появился баг, написали тест воспроизводящий баг, затем устранили, и протестировали. Этот ответ не возможно считать полным, однако я постарался максимально четко передать мой ход мыслей при создании тестов.

воскресенье, 12 января 2020 г.

Google Play Developer Console: неактивна кнопка “Перейти на бета-тестирование для группы или сообщества”

#android #google #тестирование


Коллеги, всем качественного кода.
Сегодня утром по Москве зарегистрировал аккаунт разработчика. Цель - производить
бета-тестирование приложения и обновлений к нему посредством участников сообщества
в Google+.
Итак, в консоли разработчика заполнены все поля, отвечены все вопросы, подписанный
.apk добавлен; также от учетной записи разработчика создан круг в Google+ и сообщество.
Через сообщество в Google+ отправил приглашение тестовому пользователю. Прошло больше
полудня, тестовому пользователю приглашение так и не пришло.
Выбрал вкладку "Бета-тестирование" в разделе "Файлы APK" консоли разработчика.
Нажал на кнопку "Перейти на бета-тестирование для группы или сообщества". После чего
ввел в поле электронный адрес тестового пользователя. В поле была прописана подсказка
насчет ввода электронного адреса пользователя. Но пользователь так и не был найден.
Попробовал несколько раз и после обновления страницы кнопка перестала отвечать на нажатия.
Чуть позже я прочитал о формате ввода (приведен фрагмент с официального ресурса):


  Введите адрес электронной почты группы Google или URL сообщества
  Google+, используя следующие форматы: Для группы Google:
  nazvanie_gruppy@googlegroups.com Для сообщества Google+:
  https://plus.google.com/communities/123456789012345678901


Жаль, что подобная подсказка не приведена непосредственно рядом с полем...
Честно говоря, не знаю, что и думать: в мануалах и тру-стори написано жать кнопку
"Перейти на бета-тестирование для группы или сообщества" и приглашать пользователей,
выслав им ссылку. Но кнопка почему-то не реагирует на нажатия.
Может, кто разумеет?
    


Ответы

Ответ 1



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

суббота, 11 января 2020 г.

Тестирование потоков перехват исключений java

#java #многопоточность #исключения #тестирование


Мы тестируем код и знаем, что у нас должно вывалиться исключение. К примеру мы тестируем
итератор и знаем, что больше элементов нету и если мы вызовем next (), тогда получим
NoSuchElementException, и чтобы всё было нормально мы пишем:

@Test(expected = NoSuchElementException.class)
public void shoulThrowNoSuchElementException() {
     it = new Iteratorrmatrixmass(new int[][]{});
     it.next();
}


У нас есть несколько потоков и один из потоков должен выбросить исключение OptimisticException:

@Test (expected = OptimisticException.class)
    public void update() throws InterruptedException {
        Base base = new Base(1, 1, "12321");
        Base base1 = new Base(1, 2, "");
        СacheBase data = new СacheBase();
        data.add(base);
        Thread r1 = new Thread(new Update(data, base1), "r1");
        Thread r2 = new Thread(new Update(data, base1), "r2"); // здесь должна быть
OptimisticException.class
        r1.start();
        r2.start();
        r1.join();
        r2.join();
        System.out.println(base.getVersion());
    }


Но в этом случае (expected = OptimisticException.class) эта надпись нам не помогла,
в консоли всё равно вылазит надпись:


  Exception in thread "r2" ru.job4j.blockhash.OptimisticException: Объект уже обновлён
до текущей версии, в обновлении отказано


Я полагаю из-за того, что это исключение выскакивает не в основном потоке. Что сделать
чтобы тестирование прошло успешно?
    


Ответы

Ответ 1



Есть такой "костыльный", но рабочий вариант : @Test public void test() { CompletableFuture future = CompletableFuture.runAsync(() -> { throw new OptimisticException("Optimistic Exception"); // ваш runnable код }); assertThatThrownBy(future::get) .hasCauseExactlyInstanceOf(OptimisticException.class) .hasMessageContaining("Optimistic Exception"); } Как это работает : Создается лямбда, которая выполняется когда вызывается метод get. Затем перехватывается ошибка и из нее достается исключение, которое выкинулось в вашем коде. P.S библиотека для ассертов - AssertJ

Ответ 2



Для того, что бы тест выполнился вам надо бросить исключение в текущем потоке. Чтобы обработать исключение, возникающее в потоках надо в основном потоке установить обработчик Thread.setDefaultExceptionHandler((t, e) -> { throw new OptimisticException(e); });

четверг, 9 января 2020 г.

Как можно симулировать тормозящий браузер?

#веб_программирование #тестирование


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

да это дубликат вопроса:
Изменить скорость загрузки сайта
но там нет решения моей проблемы:
    


Ответы

Ответ 1



Как вариант можно использовать какую-нибудь утилиту для искусственного ограничения скорости, например https://www.netlimiter.com/ Кроме того можно использовать встроенный аудит в Chrome: но он в основном статистику и анализ показывает, а не показывает это в реальном времени, хотя еще в network можно ограничить скорость: Еще для ограничения скорости можно использовать vpn для хрома, они чаще всего сильно рубят скорость

Ответ 2



У себя на работе при тестировании создаём ограничение 2 Гб на процесс в cgroups для Firefox и Google Chrome. Ещё ограничиваем частоту CPU с помощью cpupower set-frequency -u 1GHz -g powersave. При разработке - ограничиваем производительность средствами разработчика в Chrome (кажется с 62-й версии можно ограничивать CPU). P.S.: Работаем под Linux.

Unit-тестирование работы с файловой системой

#юнит_тесты #тестирование #test_driven_development


Возможно ли unit-тестирование класса, основная задача которого состоит во взаимодействии
с файловой системой? Ну например, мне нужно протестировать класс, который предоставляет
возможность записывать/читать биты из файла. Каким образом я могу это сделать? Можно,
конечно, записать файл с какими-то тестовыми данными, а в самом тесте проверять что
считываются именно те данные. Мне это кажется каким-то костылем. Так ли это и какие
есть еще способы протестировать работу такого класса?
    


Ответы

Ответ 1



Давайте попробуем пройтись по задачке в стиле TDD: Какие публичные методы должен иметь данный класс? Пусть это будет только чтение Read(path, offset, count) и запись Write(name, offset, count). Пока мы не пишем их код, пока нам надо придумать, как бы мы их могли протестировать? Напишем несколько тестов (которые, кстати, помогут нам более точно описать поведение и интерфейс класса): Прочитать что-то из файла и проверить, что прочиталось именно то что надо. Что должно произойти, если отдана команда прочитать 100 байт из файла размером 50 байт? Вернуть 50 байт, вернуть ошибку/исключение, или вернуть 100 байт из которых последние 50 - пустые? Выбирайте вариант и пишите на него тест. Что должно произойти, если файл не существует или недоступен? Опять же, выбирайте "правильное" поведение и пишите на него тест. Разрешаем ли мы передавать отрицательное значение offset, и что оно будет означать (например чтение с конца, а не с начала). Пишем тест. Будем ли мы поддерживать чтение/запись по локальной сети? Длинные имена файлов (260+)? Запись в системные папки (с требованием админских прав)? Что еще должно работать и что может пойти не так .. продумайте желаемое поведение и напишите на него тесты. Повторите то же для метода записи в файл. Не стремитесь сразу предусмотреть ВСЁ. Учитывайте только то что вам понадобится в обозримом будущем (согласно вашему ТЗ). Теперь можно сделать паузу, и обобщить все те моменты и тонкости которые всплыли при проектировании тестов. Окинуть их взглядом еще раз, прикинуть какие ситуации требуют приватных методов и функций, общих для чтения и записи (например, проверка существования файла, или размера). А вот только теперь можно приступать к написанию кода самого класса чтения/записи в файл! Встретили какое-то еще условие, или граничный случай в процессе разработки - отлично, напишите на него тест, а потом код. В процессе эксплуатации класса выявился баг - тоже отлично, пишите на него тест, и только потом исправляйте баг (и тестом проверяйте, что он исправлен, и что в процессе исправления ничего из другого не сломалось).

понедельник, 6 января 2020 г.

Чем удобно проверять RESTFul API?

#rest #тестирование #поиск_программ


Для проверки работы API я использую браузер. Это было удобно до того момента, как
я начал реализовывать post, put и delete методы. Мне кажется, что не стоит тратить
время на написание тулзы для проверки API. Поисковики ничего разумного не выдают по
этому поводу. Есть нормальные программы для тестирования API под win?
    


Ответы

Ответ 1



Если имеется ввиду ручное тестирование, то для браузеров имеется много плагинов для выполнения HTTP запросов. Вот например приложение для Chrome Postman

Ответ 2



Вообще, для рест нынче моден swagger. Во многих языках можно на лету генерить для него всё на основании аннотаций. К примеру, мы на ноде используем генератор самописный типо express-swagger-generator. Он по аннотациям к методу генерит данные для свагера и запускает его потом. После чего можно его открыть в браузере и выполнять любые запросы в удобном виде. Выглядит как-то так:

Ответ 3



Postman так же существует в виде отдельного приложения для Windows, Linux, MacOS. Скачать можно тут: https://www.getpostman.com/downloads/

Ответ 4



Есть такая замечательная программка как Postman, вы там можете создать запросы, указать метод. Для теста можно в запросе указать формат данных JSON, Postman вам отобразит.

четверг, 26 декабря 2019 г.

Модульное тестирование: работа с файлами

#тестирование #юнит_тесты


Как лучше всего тестировать работу с файлами? Например, я пишу тесты для класса работы
с конфигами (чтение/запись).
У него есть конструктор, в которое передается имя файла и методы get (получить значение
параметра из конфиг. файла), set (установить  значение параметра для конфиг. файла)
и commit(применить изменения). Как сделать тестирование get и set - ясно. Но как (и
надо ли) сделать работу с файлами при создании объекта и при сохранении?
PS. Также, хотелось бы увидеть наиболее интересные, с Вашей точки зрения, книги по
модульному тестированию (желательно, именно с такой теоретической информацией, без
привязки к языку; ну или применительно к java/php).
Книжку нашел вот такую. Вроде бы довольно интересная.
Спасибо.     


Ответы

Ответ 1



Сам недавно столкнулся с подобной проблемой. Правда в связке .net+sqlite+nunit если интересно будет вот ссылка на статью Test a DataReader.

вторник, 24 декабря 2019 г.

Web сервер с функциями отладки

#сеть #веб_сервер #тестирование


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

Сейчас используется два подхода - с применением утилит на подобии clumsy, которые
вносят сбои на уровне сетевого адаптера, и ручное снятие процесса веб сервера flask
(для симуляции обрыва соединения).

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

Из видимых решений - писать свой web сервер, взяв например за основу mongoose.

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


Ответы

Ответ 1



я бы воспользовался вот этим http://www.haka-security.org/ или прокси-сервером/скриптом. Не думаю, что вам будет сложно наваять прокси-скрипт, который пробрасывает соединения, обрывает их, когда нужно, либо возвращает нужную вам ошибку, спит время от времени (или по настройкам вашего теста - для детерминированности), и уж во всяком случае, это проще и надежней, чем кастомный веб-сервер

воскресенье, 22 декабря 2019 г.

Можно ли где-то онлайн протестировать сайт на высоких dpi?

#тестирование #веб_программирование


Например, чтобы увидеть, как будет выглядеть сайт на retina (с удвоенной плотностью
пикселей), если доступ к настоящим айфонам отсутствует?    


Ответы

Ответ 1



С помощью Firefox 1) Откройте адрес "about:config" и подтвердите изменение настроек 2) Найдите параметр "layout.css.devPixelsPerPx" и смените его значение на 2 3) Перейдите на нужную страницу или обновите текущую Чтобы вернуть стандартный режим, нужно сменить значение этого же параметра на 1. С помощью Google Chrome О встроенной эмуляции ретина-устройств

четверг, 19 декабря 2019 г.

Как правильно тестировать исключение?

#java #junit #тестирование


Есть некая функция DoIt, на которую пишется тест (JUnit). Если передать аргумент
null, функция должна выкинуть исключение. Я проверяют так:
public final void TestDoIt() {
    try {
        // Вызываю функцию
        DoIt(null);
        fail("doit(null) должна выкинуть исключение");
    } catch (NullPointerException e) {
    }
}

Это правильно или можно как-то лучше?
    


Ответы

Ответ 1



Это правильно для JUnit до версии 4. В новых версиях можно (и нужно) использовать аннотации: @Test(expected = NullPointerException.class) public final void doIt() { DoIt(null); }

среда, 18 декабря 2019 г.

Когда нужно начинать писать Unit тесты?

#тестирование #юнит_тесты #nunit


Дано: некая функция, которая пишется и отлаживается в LINQPad.
Отладочный вывод через Dump. Пока 4 вызова.

Вопрос: есть ли какие-нибудь эвристики, по которым можно определить, что уже нужно
начать писать юнит-тесты. Нужны какие-то критерии сложности, которые оправдывают применение
NUnit(Lite). Стабов и моков пока нет.
    


Ответы

Ответ 1



Unit tests Для начала, юнит-тесты - это тестирование в изоляции, когда класс тестируется отдельно от остального кода (то есть, от других классов). Для изоляции классов друг от друга используется IoC (Inversion of Control), и обычно это DI (Dependency Injection). Соответственно, чтобы это по настоящему работало, хорошо бы знать, что такое IoC и DI. Но, продолжая про юнит-тесты: следуя тестированию в изоляции, Вы не сможете написать тест, который тестирует один класс, если тот жестко зависит от другого. Вернее, конечно, сможете, но это будет не юнит-тест, а интеграционный (но, замечу, что есть некоторая путаница с определениями, что такое интеграционный тест). Если же Вы тестируете некую функцию на наборе реальных данных, то это - функциональное тестирование (но, опять же, есть некоторая путаница с определениями). И то, и другое, можно сделать при помощи того же NUnit, но не стоит путать их с юнит-тестами, они служат для разных целей! Для чего нужны юнит-тесты: для упрощения создания хорошей архитектуры. Которая, в свою очередь нужна для облегчения внесения изменений в код. Иными словами, для облегчения ведения гибкой разработки (agile), для облегчения поддержки и так далее. Для чего нужны функциональные тесты: для тестирования работы отдельных частей системы на реалистичных данных, чтобы избежать багов, связанных с вычислениями. Для чего нужны интеграционные тесты: для тестирования системы или ее подсистемы в сборе, чтобы убедиться, что она выполняет то, что от нее требуется ее пользователям. TDD TDD правильно было бы перевести на русский, дословно, как "разработка, приводимая в движение тестированием", это сделало бы понимание чуть проще. Делается оно примерно так: Вы осознаете, что Вам нужно написать класс. Вы пишете один юнит-тест (сразу нацеливаясь на IoC и DI) на метод класса. Вы пишете класс и тестируемый метод в объеме, достаточном, чтобы тест прошел. Повторяете пункты 2-3 до тех пор, пока класс не будет готов. Профит: класс, не связанный с другими классами - готов. Функциональный тест может писаться на этом этапе, если тестируемые методы не зависят от результата работы других классов. Интеграционные тесты можно писать, когда написана сама (под)система, которая уже может выполнять некую работу и обладает неким интерфейсом, к которому предполагается обращение "снаружи" этой системы, в том числе, и пользователем. Вот этот интерфейс и нужно тестировать, в том числе и на реалистичных данных. Когда стоит начинать писать тесты Если Вы пишете небольшой проект в течение 1-3 месяцев, а затем особое увеличение кода в нем не предполагается, то можно особо не заморачиваться с юнит-тестами. Проект достаточно мал, чтобы внесение изменений и правка багов не стали для него фатальны. Имеет смысл написать какие-то функциональные/интеграционные тесты на сложные алгоритмы. Но, тут важно грамотно оценить потенциал роста проекта. Если же предполагается достаточно длительная разработка, поддержка, возможно изменение требований и так далее, то тестирование необходимо, иначе Вы в итоге Вы получите кучу проблем на позднем этапе разработки проекта (обычно получается дикая лапша, в которой просто страшно что-то менять, так как сломаться после изменений может что угодно). В таком случае юнит-тесты стоит начинать писать сразу же. Единственное исключение - это прототипы (например, прототипы часто пишут в геймдеве, чтобы попробовать механику, посмотреть графику, показать инвесторам и т.п.). Важно помнить, что код прототипа не должен уйти в продакшн как есть, без переписывания по всем правилам! В Вашем случае, Вы можете написать функциональные тесты, и, возможно, интеграционные, если есть, с чем. Если, как Вы пишете в комментариях, функция будет встраиваться в большой проект, имеет смысл следовать правилам проекта.

Ответ 2



Всё просто: подумайте насколько крупным будет ваш проект, и как часто будет требоваться менять что-то в нем. Одноразовая утилита, написанная на коленке за 5 минут? Можете спокойно забыть про юнит-тесты! Это пустая трата времени. Средний или относительно крупный проект, который будет активно изменятся в будущем, и/или который кто-то кроме вас будет поддерживать? Начинайте писать юнит-тесты до ещё до начала работы над основным кодом проекта! Они очень упростят тестирование в момент разработки, да изменение кода после его перехода на поддержку.