четверг, 29 мая 2014 г.

Тестируем калькулятор № 6.1. Тестирование с использованием эталонов

Глава 0.
Глава 1.
Глава 2.
Глава 3.
Глава 4.
Глава 5.

В прошлой главе мы перешли от тестирования GUI формы, к тестированию бизнес-логики, выделив класс бизнес логики TCalculator.

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

Постараюсь более детально объяснить на примере написания эталонного теста к операции + или как она записана у нас в калькуляторе функция ADD.

пятница, 23 мая 2014 г.

Offtopic. Offtopic. Про "оружие" и "демократию". Напишу бред

Вот вы умеете БТР водить? И я - НЕТ! А вот "ополченцы" из ДНР - УМЕЮТ! Скажете это "засланцы России"? Может БЫТЬ! Но по-моему - всё проще - люди - "банально служили"... Ещё при СССР.. Есть ещё вопросы "что такое всеобщий призыв" и "зачем он нужен"?
Кстати в Германии и в Израиле "призыв" таки - есть.. ДЛЯ ВСЕХ...
Надо продолжать?
Разовью тему...
Если ВЛАСТЬ ХОЧЕТ, чтобы "народ не мешался", то она ратует за "профессиональную армию", а если ВЛАСТЬ это - РЕАЛЬНАЯ "демократия" и НЕ БОИТСЯ своего народа, то она РАТУЕТ за "всеобщий призыв"...
Мысль понятна?
БТР я водить не умею.. К сожалению.. Но автомат - разобрать и собрать - могу...
И в мишень даже когда-то - попадал...
Кожугетычу - дай бог здоровья.. Он может чего и выправит..

Ещё раз ссылка. Мартин Фаулер. Предметно-ориентированные языки программирования

http://namerec.blogspot.ru/2014/04/blog-post.html

Что сказать...

Выглядит - КРУТО и ВНУШАЮЩЕ...

Но!

Я попробовал применить подобную технику в своих проектах.

Что могу сказать?

Мне ЛИЧНО - неудобно.

Очень сложно отлаживать. Break-point'ы ставятся на "всю вязанку" выражения, а не на конкретные строки.

Посему - мне ЛИЧНО - неудобно.

Но выглядит - "ЗАМАНЧИВО".

Ссылка. Don’t repeat yourself

http://ru.wikipedia.org/wiki/DRY

"Принцип DRY, известный также как Single Source of Truth (англ.), превалирует в Model Driven Architecture-системах, в которых артефакты программы извлекаются из главной модели объекта и выражаются в такой форме, как UML."

;-)

Поставил Delphi XE6

Поставил наконец Delphi XE6.

Ничего так...

ВСЕ проекты - СОБРАЛИСЬ.

Не скажу, что ВСЕ заработали, но ВСЕ - собрались.

Некоторые даже - заработали...

среда, 21 мая 2014 г.

Тестируем калькулятор №5. Тесты через "новую архитектуру"

Здравствуйте читатели.
Александр любезно предоставил мне  "площадку" для понимания TDD.
Постижение написания кода через тестирование под руководством опытного наставника... Что может быть приятней :).

Небольшая преамбула:
18 февраля Всеволод Леонов предложил Александру показать каким образом приложение которое не задумывалось для тестирования превратить в full-testable system.
Приложением для примера был выбран обычный калькулятор:
Проект был банален до невозможности, 4 кнопки 3 Edit.

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

Первым делом добавляем к приложению тесты(DUnit), детали описаны здесь.
Следующим шагом Александр "посещает форму, присваивает 2 значения Едитам и проверяет кнопку Плюс".
Третий этап означал расширение тестов от одной операции(Плюс) до покрытия всех кнопок. Александр при этом выделил абстрактный класс - TOperationTest. В комментариях к этому посту развернулась довольно интересная дискуссия по поводу выделения абстрактного класса, зачем и почему читатели узнают из будущих постов :)
В четвертом посте Александр выделил класс "бизнес-логики" -  TCalculator, в котором находятся функции для расчета всех операций калькулятора.

Ну а сегодня мы обсудим тестирование логики нашего приложения.
После изменений архитектуры мы можем протестиорвать непосредственно "логику приложения". Поэтому. Самый простой способ сделать это сейчас это написать класс TCalculatorOperation отнаследованный от TTestCase и проверить все операции. Я правда ещё и проверил ошибочность выполнения в одной из операций. Но я думаю что если читателям будет интересно то эту тему мы обсудим в комментариях.
Собственно код:
unit CalculatorOperationTest;

interface

uses
  TestFrameWork,
  Calculator
  ;

 type
  TCalculatorOperationTest = class(TTestCase)
   published
    procedure LogicTestDiv;
    procedure LogicTestMul;
    procedure LogicTestAdd;
    procedure LogicTestSub;
    procedure LogicTestSubError;
  end;//TCalculatorOperationTest

implementation

  uses
   SysUtils;

const
 cA = '5';
 cB = '10';
{ TCalculatorOperationTest }

procedure TCalculatorOperationTest.LogicTestDiv;
var
  x1, x2  : string;
  result : Single;
begin
  x1:= cA;
  x2:= cB;
  result := StrToFloat(TCalculator.Divide(x2, x1));
  CheckTrue(2 = result);
end;

procedure TCalculatorOperationTest.LogicTestSub;
var
  x1, x2  : string;
  result : Single;
begin
  x1:= cA;
  x2:= cB;
  result := StrToFloat(TCalculator.Sub(x2, x1));
  CheckTrue(5 = result);

end;

procedure TCalculatorOperationTest.LogicTestSubError;
var
  x1, x2  : string;
  result : Single;
begin
  x1:= cA;
  x2:= cB;
  result := StrToFloat(TCalculator.Sub(x2, x1));
  CheckFalse(7 = result);
end;

procedure TCalculatorOperationTest.LogicTestMul;
var
  x1, x2  : string;
  result : Single;
begin
  x1:= cA;
  x2:= cB;
  result := StrToFloat(TCalculator.Mul(x2, x1));
  CheckTrue(50 = result);
end;

procedure TCalculatorOperationTest.LogicTestAdd;
var
  x1, x2  : string;
  result : Single;
begin
  x1:= cA;
  x2:= cB;
  result := StrToFloat(TCalculator.Add(x2, x1));
  CheckTrue(15 = result);
end;

initialization
 TestFramework.RegisterTest(TCalculatorOperationTest.Suite);
end.

Таким образом мы ушли от "тестирования GUI" к тестированию "бизнес логики".


upd1. Залил исходнки на BitBucket.

вторник, 20 мая 2014 г.

Ссылка. Ещё от Теплякова

https://plus.google.com/+SergeyTeplyakov/posts/jHy5AMQGgCs

"Очень часто наличие интерфейсов объясняется не только желанием протестировать класс в изоляции, но и попыткой дать возможность заменить компонент без перекомпиляции приложения. Этот момент очень классно прокритиковал Кент и Дэвид: попытка заменить слой доступа к данным и заменить базу данных веб-сервисом, или in-memory DB на практике невозможна, поскольку каждая из этих реализаций обеспечивает слишком разные характеристики с точки зрения надежности или времени исполнения. На практике даже переход от одной реляционной СУБД на другую оказывается сложным или невозможным, не говоря уже о таких принципиальных сменах «деталей реализации»."

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

Ссылка. Бертран Мейер. Объектно-ориентированное конструирование программных систем

http://sergeyteplyakov.blogspot.co.uk/2012/03/blog-post_19.html

"Во-вторых, все примеры даются на языке Eiffel. Сам по себе язык очень интересный и тот факт, что за последние 20 лет в него не внесли никаких концептуальных изменений, говорит о том, что язык с самого начала был очень хорошо продуман. Но поскольку большинство современных ОО-языков не поддерживают некоторые ключевые ОО-возможности (с точки зрения Мейера), то далеко не все описываемые концепции удастся пощупать на практике (в основном это касается отсутствия множественного наследования и проектирования по контракту).
Книга Мейера действительно является лучшей книгой по ООП и отличным трудом по разработке ПО в целом. Эта книга – отличный способ получить много новых знаний и навести порядок с уже существующими. А еще это отличный способ поразмышлять над интересными вопросами и начать думать о проектировании ПО более формальным образом. Так что потратьте на нее немного своего бесценного времени, не пожалеете."

пятница, 16 мая 2014 г.

Сегодня закончил писать тест к "вообще нетестируемому коду"

Сегодня закончил писать тест к "вообще нетестируемому коду".

Приходу сообщений по TCP/IP и их обработке.

Вполне успешно.

Съэмулировал создание, отправку и получение сообщений в рамках одного приложения, а не распределённой системы.

четверг, 15 мая 2014 г.

Кодогенерация.. коротко ЗАЧЕМ

пример про кодогенерацию - я СЕГОДНЯ поменял имя метода в БАЗОВОМ классе.. виртуального.. и в течении 5-ти минут в СТА других классах всё поменялось.. за счёт кодогенерации..

При ЛЮБЫХ других раскладах я бы потратил бы день-два...

Про ПРИМЕСИ - "умолчу"... Я взял и часть функционала одного КОНКРЕТНОГО класса выделил в ПРИМЕСЬ и примешал её к пяти другим классам. Не связанным наследованием с исходным классом. И всё "завелось" за 5-ть минут.

Ещё раз ссылка. Тепляков

http://sergeyteplyakov.blogspot.ru/

За что я "люблю" Теплякова? За то, что он ничего не "постулирует" и ничего не "критикует".

На мой вкус.

Он лишь "разбирает" и "высказывает своё мнение". Как-то так.

А уж его перевод ""C++ 11 FAQ от Бьярна Страуструпа" - http://sergeyteplyakov.blogspot.ru/2012/05/c-11-faq.html - по-моему - бесподобен

Ссылка. Экс-глава ЦРУ и АНБ: Мы убиваем людей, используя метаданные

http://russian.rt.com/article/31734

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

"«На дебатах в университете Джонса Хопкинса, мой оппонент генерал Майкл Хайден сказал: «мы убиваем людей, используя метаданные», — сообщил профессор телезрителям.
По его мнению, сбор метаданных представляет опасность для простых граждан. «Конечно, содержание разговоров может быть решающим при какой-либо угрозе. Но метаданные сами по себе создают чёткую картину самых личных интересов и круга знакомств человека, в реальности намного проще изучать метаданные миллионов звонков, чем обрабатывать их содержание. Бывший руководитель АНБ Стюар Бейкер ранее заявил, что метаданные говорят вам абсолютно всё о чей бы то ни было жизни. Если у вас есть метаданные звонков, содержание этих разговоров вам и не нужно», — отметил профессор."

Ну и умный человек по сему поводу пишет:

"Не знаю почему, но интуитивно мне представляется, что в этом сообщении - нечто важное. Концептуально важное...
Действительно, если вам известны метаданные, то для качественных выводов о данных, правдоподобных предположений о них, сами данные не нужны...
Действительно, положим, вам известна структура некоторой таблицы. имена полей, их типы, название таблицы наконец... Неужели нельзя сделать правдоподобное заключение о том, что за данные будут храниться в этой таблице и приблизительно сколько их будет?
Почему-то не приходило в голову, что так можно и с телефонными разговорами... И с почтовой перепиской, и много ещё с чем. И не нужны вычислительные мощности космических масштабов...
Если один раз хорошо подумать, можно серьёзно сэкономить...
Права была всё-таки моя учительница по физике, когда говорила, что "дурака работа любит"... Умного же она избегает, вероятно... :-)
Оказывается, поучиться можно и у АНБ... :-)"

Согласен на все 100%

Ссылка. Критерии плохого дизайна

http://sergeyteplyakov.blogspot.ru/2013/01/blog-post_29.html

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

есть один БОЛЬШОЙ фактор - "программист должен САМ вырасти над собой"...

и НИКТО ему в этом не поможет...

это я по своему опыту говорю

ЛЮБОГО программиста можно "учить" умно и "правильно" и он будет СЛУШАТЬ, но он НЕ СТАНЕТ "копией вас", он САМ ВЫРАСТЕТ... Сам "набив свои шишки".. И только так...

Ссылка. Модульный тест: определение

http://sergeyteplyakov.blogspot.ru/2014/05/unit-testthe-definition.html

Особенно вот что понравилось:

"DIP - это не решение проблемы в данном случае. Это ее причина. Подробнее - в статье "Критика DIP""

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

И ещё к вопросу об ARC

По мотивам - http://programmingmindstream.blogspot.ru/2014/05/arc.html

Пусть мы печатаем документ.

И пусть мы делаем это используя не TCanvas, а ICanvas.

И пусть "машина печати" имеет свойство Canvas типа ICanvas.

Так вот.

500 страниц Налогового Кодекса с 40-ка параграфами на страницу приводит вот к чему.

Как минимум для каждого параграфа мы получаем канву и сохраняем её в локальную переменную.

Это - 500*40*2 = 40000 операций InterlockedIncrement/Decrement. За "просто так".

Понятное дело, что можно и по-другому оптимизировать. Например не получать канву "на каждый чих". И при этом не забывать ставить модификатор const перед ВХОДНЫМИ интерфейсными параметрами. Ибо если не поставить const то имеем пару InterlockedIncrement/Decrement.

К вопросу об ARC...

Я тут закончил "большую переделку".

"Зачем-то"...

Избавился от использования интерфейсов на большинстве базовых классов. В пользу использования примесей и абстрактных классов.

Что сказать. Результат - превзошёл ожидания.

Производительность увеличилась на 30%. (Естественно далеко не на ВСЕХ прецедентах)

И это только за счёт отказа от "паразитного" подсчёта ссылок "на каждый чих".

(Читай отказался от InterlockedIncrement/Decrement)

Только и всего.

Наиболее заметно это на "операциях ввода/вывода", а ОСОБЕННО - отрисовки данных на канве.

Вот так вот...

Теперь я погружён в УНЫНИЕ...

Ведь НАМ "светит ARC"...

Всем и "в вену"...

Где всё те же - "паразитный подсчёт ссылок" и InterlockedIncrement/Decrement.

Светит.

И куда от этого уйти? Или к тому моменту "рост мощностей" нивелирует данные потери?

P.S. Кстати.. Есть вопрос к ЗНАТОКАМ. А атрибут [Weak] для локальных переменных работает?

P.P.S. Возвращаясь к интерфейсам... Хочу отметить, что отказ от них позволил съэкономить как минимум по 4-ре байта на каждый класс (где был произведён отказ от интерфейсов). Немного.

Налоговый кодекс занимает примерно 500 страниц. На каждой странице примерно 40 параграфов. Соответственно на НК съэкономлено примерно 80 Кб. Немного.