Юнит-тестирование Lua-кода при помощи TAP. Илья Чесноков

Similar documents
Oracle Object-Relational Features. Пыхалов А.В. ЮГИНФО

ОБЪЕКТНО- ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ. Лекция 1 / г.

Managing PKI Deployments. WhiteRabbitSecurity

runs all the testscripts named as arguments and checks standard output for the expected strings in TAP format.

ORM/Hibernate. Hibernate - это один из самых популярных на сегодняшний день ORM-фреймворков.

of data is not limited, no matter how much data you upload or access from your servers the connection capacity remains high.

TypeScript. Часть II. Старков Дима

A Tour of Perl Testing

Основы Java для разработки приложений для Android. Версия 7 AND-404

# Rather than print STDERR "# here's what went wrong\n" diag("here's what went wrong");

LuaUnit Documentation

Обзор веб-сайта alltechnews.net

C++17. Antony Polukhin Полухин Антон

Карта «Кофейные регионы Эфиопии» Коллеги из Trabocca любезно предоставили нам карту кофейных регионов Эфиопии, за что

ОБЛАЧНЫЙ ДЕМОЗАЛ. Легко находите KIP Sales, Marketing и технические ресурсы по продукту.

Lizardtech djvu document express editor 6.0 pro portable. Lizardtech djvu document express editor 6.0 pro portable.zip

Module 1 Introduction to Information Storage

жидкость и пневматика Rectus 86/87/88 Быстроразъемные соединения для термостатирования пресс-форм

Nina Popova, St.Petersburg Polytechnic University Liudmila Devel, St.Petersburg University of Culture.

Tvheadend - Feature #4459 exported m3u playlist - add group-title= parameter

Новые возможности финансирования (следующие конкурсы FP7-ICT практические советы, инструменты поддержки Idealist2011

Apache Kafka и реактивные микросервисы на.net Core. Денис

Результат запроса: bonfire knife party скачать

PolygonMap Help. Contents

Основы Perfect Developer

Tarantool. Выпуск 1.9.0

Максим Грамин КРОК. В поисках идеального инструмента

lab9 task1 nets: Пажитных Иван Павлович 3 курс, 1 группа, МСС github lab link ip/mask /26 ip mask

subtest $builder->subtest($name,

3D ray tracing simple scalability case study

LoadDataToDataGrid();

3M Human Resources Talent Acquisition

Verification of System on Chip Integrated Communication Controllers

Instruction for use Инструкция по эксплуатации UMPCB RU. POWERTEX Chain Block model PCB-S1

Семинар 4 (26) Программирование сопроцессора Intel Xeon Phi (MPI)

ОБЗОР СЕРИИ IMAGERUNNER ADVANCE C35XX II

Баум Виталий Sr. SharePoint Developer Conteq

Лист 1 RU С-US.ГБ08.B.02500

Veeam Backup & Replication

Configure Dr.Web to protect your computer from miners

NodeBB Documentation. Выпуск The NodeBB Team (

New Replication Features MySQL 5.1 and MySQL 6.0/5.4

Методика записи платы М101 для концентратора KP-8 и абоненского выноса AV Подключить jtag, включить плату и запустить программу jtag

Vk boys dropbox files

A Model-Based Approach to Design Test Oracles for Memory Subsystems of Multicore Microprocessors

Boundary-Based Interval Newton s Method. Интервальный метод Ньютона, основанный на границе

Evalua'ng the internet end- user experience in the Russian Federa'on Ini'al Findings

Build scripts - DBD-Oracle 1.21 against Windows Perl 5.6.1

Reversible Data Hiding Using a Histogram Modification

Руководство по быстрой установк

Подключение ультразвукового датчика HC-SR04

ExtJS 3.0. ExtJS Cookbook

1:1 A5 白底黑字, 80g 双胶纸.

Cloud mail ru dropbox

Олимпиада по информатике

Cisco Connect. Москва, Цифровизация: здесь и сейчас

3I, a new program for creating Internet-accessible interactive keys and taxonomic databases and its application for taxonomy of Cicadina (Homoptera)

JS_3. Формы. Графики. GitHub. Трубочкина Н.К.

AnyConnect по IKEv2 к ASA с AAA и проверкой подлинности сертификата

1: epplus 2 2: 5 3: 8 4: 9 5: 12

TESTING TOOLS. Standard Suite

Math-Net.Ru All Russian mathematical portal

THC Control 2.0 Plasma Cutting System Control Software

Math-Net.Ru All Russian mathematical portal

KAK - Event ID 1004 Terminal Services Client Access License (TS CAL) Availability

hp g62 instructions FF495F187D5CF C61864FC99F9 Hp G62 Instructions 1 / 6

или "Преобразование IP адресов в доменные имена в отчетах LightSquid"

Zigmund & Shtain. Zigmund & Shtain CZ N L

MONTHLY MAGAZINE RUSSIAN SWITZERLAND

TL-PA2010 AV200 Nano Powerline Adapter

MANAS Journal of Engineering. Volume 6 (Issue 1) (2018) Pages Outdoor People Tracking

Math-Net.Ru All Russian mathematical portal

Pontificating on Perl Profiling. Lisa Hagemann VP Engineering, Dyn Inc. twitter.com/lhagemann twitter.com/dyninc

Семинар 1 (23) Программирование сопроцессора Intel Xeon Phi

USING THE GENSYS SOFTWARE FOR RAILWAY VEHICLE MODELING

IoT Security Platform

Student Outcomes. Lesson Notes. Classwork. Example 2 (3 minutes)

$t = timeit($count, '...other code...') print "$count loops of other code took:",timestr($t),"\n";

Jsonb «smart» indexing. Parametrized opclasses

Math-Net.Ru All Russian mathematical portal

HIGH-QUALITY HARDWARE ACCELERATED VISUALIZATION OF PARTICULATE MATERIALS

Оптимизация запросов в PostgreSQL - live at PG Day. Алексей Ермаков Илья Космодемьянский

КИБЕРНЕТИКА И МЕХАТРОНИКА

(TrueType)"="seguili.ttf" "Segoe UI Semibold (TrueType)"="seguisb.ttf" "Segoe UI Semibold Italic (TrueType)"="seguisbi.ttf" "Segoe UI Semilight

Analysis System of Scientific Publications Based on the Ontology Approach

Краткое руководство по установке

Приложение IRC 117 E от

XML Model for Legal Documents

Visual Quality Increasing using Image Parts Improvement for Fractal Image Compression

Collateral damage of Internet content blocking. ENOG14, Samorukov, Netart Group, Isavnin, Internet Protection Society

USER MANUAL(GB)...P03 РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ(RU)...P08 CMY

FULL GUIDANCE AND TUTORIAL: HOW TO MAKE A DIY SELFIEBOT

Vk cloud mail ru links

DSL-2640U Wireless ADSL2/2+ 4-port

Math-Net.Ru All Russian mathematical portal

Approach on Applications of Random High Data Flows Concerning the Architecture of Computer Networks

Консультант в Miles. Работаю с F# и Демо презентации: AkkaStreamsDemo

Как развернуть кампусную сеть Cisco за 10 минут? Новые технологии для автоматизации и аналитики в корпоративных сетях Cisco.

Higher Order Perl. Finlay Thompson. 14 March 2006

Math-Net.Ru All Russian mathematical portal

Transcription:

Юнит-тестирование Lua-кода при помощи TAP Илья Чесноков

Все началось...!2

С маленькой программки на Lua!3

...несколько юнит-тестов...!4

lua-testmore!5

Test Anything Protocol (TAP)!6

Test Anything Protocol (TAP) Текстовый интерфейс между тестовыми модулями и средой Во многих ЯП есть библиотеки для генерации Потребляется большинством CI-систем!7

TAP output 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet!8

TAP output: test plan 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet!9

TAP output: test result 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet!10

TAP output: test number 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet!11

TAP output: description 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet!12

TAP output: directives 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet!13

To plan or not to plan?!14

t/plan2.lua #!/usr/bin/env lua require 'Test.More' plan(2) pass('first test') pass('second test') pass('third test')!15

t/plan2.lua #!/usr/bin/env lua require 'Test.More' plan(2) pass('first test') pass('second test') pass('third test')!16

t/plan2.lua #!/usr/bin/env lua require 'Test.More' plan(2) pass('first test') pass('second test') pass('third test')!17

lua t/plan2.lua 1..2 ok 1 - First test ok 2 - Second test ok 3 - Third test!18

prove -vm t/plan2.lua t/plan2.lua.. 1..2 ok 1 - First test ok 2 - Second test ok 3 - Third test All 2 subtests passed Test Summary Report ------------------- t/plan2.lua (Wstat: 0 Tests: 3 Failed: 1) Failed test: 3 Parse errors: Bad plan. You planned 2 tests but ran 3. Files=1, Tests=3, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!19

prove -vm t/plan2.lua t/plan2.lua.. 1..2 ok 1 - First test ok 2 - Second test ok 3 - Third test All 2 subtests passed Test Summary Report ------------------- t/plan2.lua (Wstat: 0 Tests: 3 Failed: 1) Failed test: 3 Parse errors: Bad plan. You planned 2 tests but ran 3. Files=1, Tests=3, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!20

t/done_testing.lua require 'Test.More' pass('first test') pass('second test') pass('third test') done_testing()!21

prove -vm t/done_testing.lua t/plan2.lua.. ok 1 - First test ok 2 - Second test ok 3 - Third test 1..3 ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS!22

Директива TODO!23

t/todo.lua require 'Test.More' pass('passing test') todo('will fix later', 1) fail('failing test') done_testing()!24

prove -vm t/todo.lua t/todo.lua.. ok 1 - Passing test not ok 2 - Failing test # TODO Will fix later # Failed (TODO) test (t/todo.lua at line 7) 1..2 ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.04 usr + 0.01 sys = 0.05 CPU) Result: PASS!25

prove -vm t/todo.lua t/todo.lua.. ok 1 - Passing test not ok 2 - Failing test # TODO Will fix later # Failed (TODO) test (t/todo.lua at line 7) 1..2 ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.04 usr + 0.01 sys = 0.05 CPU) Result: PASS!26

prove -vm t/todo.lua t/todo.lua.. ok 1 - Passing test not ok 2 - Failing test # TODO Will fix later # Failed (TODO) test (t/todo.lua at line 7) 1..2 ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.04 usr + 0.01 sys = 0.05 CPU) Result: PASS!27

Директива SKIP!28

t/skip_all.lua require 'Test.More' local Redis = require 'redis' if not pcall(redis.connect) then skip_all('redis is not available') end --... done_testing()!29

t/skip_all.lua require 'Test.More' local Redis = require 'redis' if not pcall(redis.connect) then skip_all('redis is not available') end --... done_testing()!30

prove -vm t/skip_all.lua t/skip_all.lua.. skipped: Redis is not available Files=1, Tests=0, 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) Result: NOTESTS!31

prove -vm t/skip_all.lua t/skip_all.lua.. skipped: Redis is not available Files=1, Tests=0, 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) Result: NOTESTS!32

testanything.org!33

Test.More!34

Test.More asserts ok(got, title) - проверка на true is(got, expected, title) - проверка got == expected like(got, pattern, title) - проверка на regex cmp_ok(this, op, that, title) - сравнение оператором op и др.!35

Test.More asserts ok(got, title) - проверка на true is(got, expected, title) - проверка got == expected like(got, pattern, title) - проверка на regex cmp_ok(this, op, that, title) - сравнение оператором op и др.!36

Пример: lib/adder.lua return { -- add() - sums up 2 numbers and returns result add = function(x, y) return x + y end }!37

t/adder.lua -- Export all the Test.More functions as globals require('test.more') local adder = require('adder') plan(2) -- Plan 2 tests is(adder.add(2.0001, 1.9999), 4, '2.0001 + 1.9999 == 4') is(adder.add(1e100, 2e100), 3e100, '1e100 + 2e100 == 3e100')!38

t/adder.lua -- Export all the Test.More functions as globals require('test.more') local adder = require('adder') plan(2) -- Plan 2 tests is(adder.add(2.0001, 1.9999), 4, '2.0001 + 1.9999 == 4') is(adder.add(1e100, 2e100), 3e100, '1e100 + 2e100 == 3e100')!39

t/adder.lua -- Export all the Test.More functions as globals require('test.more') local adder = require('adder') plan(2) -- Plan 2 tests is(adder.add(2.0001, 1.9999), 4, '2.0001 + 1.9999 == 4') is(adder.add(1e100, 2e100), 3e100, '1e100 + 2e100 == 3e100')!40

t/adder.lua -- Export all the Test.More functions as globals require('test.more') local adder = require('adder') plan(2) -- Plan 2 tests is(adder.add(2.0001, 1.9999), 4, '2.0001 + 1.9999 == 4') is(adder.add(1e100, 2e100), 3e100, '1e100 + 2e100 == 3e100')!41

prove -vm t/adder.lua!42

t/adder.lua.. 1..2 ok 1-2.0001 + 1.9999 == 4 not ok 2-1e100 + 2e100 == 3e100 # Failed test (t/adder.lua at line 10) # got: 3e+100 # expected: 3e+100 Failed 1/2 subtests Test Summary Report ------------------- t/adder.lua (Wstat: 0 Tests: 2 Failed: 1) Failed test: 2 Files=1, Tests=2, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!43

Программа выросла: больше юнит-тестов!44

Пожелания для юнит-тестирования Структуризация Один класс / модуль один тестовый файл Один метод класса один тестовый метод Повторное использование кода в ООП-стиле Возможность подготовки / очистки тестовых данных Запуск тестов для отдельного класса / метода!45

Лаконичные assert-ы Структуризация Наследование Подготовка/ очистка данных Выборочный запуск Test.More!46

Lua-фреймворки Busted LuaUnit Telescope, lunit,... http://lua-users.org/wiki/unittesting!47

Busted!48

Busted asserts: luassert assert.is_true(got), assert.is_not.true(got),... assert.are.equal(expected, got),... assert.has.errors(function() error("this should fail") end)...!49

Busted asserts: luassert Можно добавлять свои assert-ы Поддерживаются моки, асинхронные тесты и т.д.!50

busted/adder_spec.lua require('busted.runner')() local adder = require('adder') local assert = require('luassert') describe("function add()", function() it('can add 2.0001 and 1.9999', function() end) assert.are.equal(4, adder.add(2.0001, 1.9999)) it('can add 1e100 and 2e100', function() assert.are.equal(3e100, adder.add(1e100, 2e100)) end) end)!51

busted/adder_spec.lua require('busted.runner')() local adder = require('adder') local assert = require('luassert') describe("function add()", function() it('can add 2.0001 and 1.9999', function() end) assert.are.equal(4, adder.add(2.0001, 1.9999)) it('can add 1e100 and 2e100', function() assert.are.equal(3e100, adder.add(1e100, 2e100)) end) end)!52

busted/adder_spec.lua require('busted.runner')() local adder = require('adder') local assert = require('luassert') describe("function add()", function() it('can add 2.0001 and 1.9999', function() end) assert.are.equal(4, adder.add(2.0001, 1.9999)) it('can add 1e100 and 2e100', function() assert.are.equal(3e100, adder.add(1e100, 2e100)) end) end)!53

.busted return { _all = { output = 'TAP', }, }!54

prove -vm busted/adder_spec.lua!55

busted/adder_spec.lua.. ok 1 - Function add() can add 2.0001 and 1.9999 not ok 2 - Function add() can add 1e100 and 2e100 # busted/adder_spec.lua @ 13 # Failure message: busted/adder_spec.lua:14: Expected objects to be equal. # Passed in: # (number) 3.000000000000000242e+100 # Expected: # (number) 2.9999999999999998534e+100 1..2 Dubious, test returned 1 (wstat 256, 0x100) Failed 1/2 subtests Test Summary Report ------------------- busted/adder_spec.lua (Wstat: 256 Tests: 2 Failed: 1) Failed test: 2 Non-zero exit status: 1 Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.02 cusr 0.01 csys = 0 CPU) Result: FAIL!56

busted/adder_spec.lua.. ok 1 - Function add() can add 2.0001 and 1.9999 not ok 2 - Function add() can add 1e100 and 2e100 # busted/adder_spec.lua @ 13 # Failure message: busted/adder_spec.lua:14: Expected objects to be equal. # Passed in: # (number) 3.000000000000000242e+100 # Expected: # (number) 2.9999999999999998534e+100 1..2 Dubious, test returned 1 (wstat 256, 0x100) Failed 1/2 subtests Test Summary Report ------------------- busted/adder_spec.lua (Wstat: 256 Tests: 2 Failed: 1) Failed test: 2 Non-zero exit status: 1 Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.02 cusr 0.01 csys = 0 CPU) Result: FAIL!57

Лаконичные assert-ы Структуризация Наследование Подготовка/ очистка данных Выборочный запуск Test.More Busted!58

LuaUnit!59

LuaUnit asserts assert_true(value) / assert_false(value) assert_nil(value) / assert_not_nil(value) assert_equals(actual, expected) / assert_not_equals(actual, expected) assert_str_contains(str, sub, [, usere])...!60

luaunit/tests/testadder.lua -- Global table! TestAdder = {} local adder = require('adder') function TestAdder:test_add() assert_equals(adder.add(2.0001, 1.9999), 4) assert_equals(adder.add(1e100, 2e100), 3e100) end!61

luaunit/run_tests.lua EXPORT_ASSERT_TO_GLOBALS = true local luaunit = require('luaunit') -- Load test library require('testadder') lu = luaunit.luaunit.new() lu:setoutputtype('tap') lu:runsuite()!62

prove -vm luaunit/run_tests.lua!63

luaunit/run_tests.lua.. 1..1 # Started on Sun May 6 19:15:46 2018 # Starting class: TestAdder not ok 1 TestAdder.test_add # luaunit/tests/testadder.lua:8: expected: 3e+100, actual: 3e+100 # Ran 1 tests in 0.001 seconds, 0 successes, 1 failure Failed 1/1 subtests Test Summary Report ------------------- luaunit/run_tests.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!64

luaunit/run_tests.lua.. 1..1 # Started on Sun May 6 19:15:46 2018 # Starting class: TestAdder not ok 1 TestAdder.test_add # luaunit/tests/testadder.lua:8: expected: 3e+100, actual: 3e+100 # Ran 1 tests in 0.001 seconds, 0 successes, 1 failure Failed 1/1 subtests Test Summary Report ------------------- luaunit/run_tests.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!65

Лаконичные assert-ы Структуризация Наследование Подготовка/ очистка данных Выборочный запуск Test.More Busted LuaUnit!66

LuaUnit: особенности Каждый тест: в отдельной глобальной таблице (модуле) "by design" Тестовые сообщения задавать нельзя вообще Фреймворк "перегружен" лишними проверками и функциями!67

Что можно сделать?!68

Perl: Test::Class...!69

...основан на junit...!70

...использует Test::More!!71

Lua:...?!72

...lua-testclass!!73

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!74

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!75

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!76

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!77

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!78

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!79

t/tests/testsfor/adder.lua local _M = require('middleclass')('testsfor.adder', require('test.class')) require('test.more') local adder = require('adder') function _M:test_add() is(adder.add(2.0001, 1.9999), 4, '2.0001 plus 1.9999 equals 4') is(adder.add(1e100, 2e100), 3e100, '1e100 plus 2e100 equals 3e100') end return _M!80

t/tc.lua require('testsfor.adder') local tc = require('test.class') tc.run_tests()!81

prove -vm t/tc.lua!82

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!83

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!84

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!85

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!86

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!87

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!88

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!89

t/tc.lua.. # Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # Failed test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 not ok 1 - test_add # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 53) 1..1 not ok 1 - TestsFor.Adder # Failed test (/Users/ichesnokov/git/lua-TestClass/lib/Test/Class.lua at line 18) 1..1 Failed 1/1 subtests Test Summary Report ------------------- t/tc.lua (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL!90

Добавим ещё один класс!91

lib/subtractor.lua return { -- subtract() - subtracts y from x and returns result subtract = function(x, y) return x - y end }!92

t/tc.lua require('testsfor.adder') require('testsfor.subtractor') local tc = require('test.class') tc.run_tests()!93

# Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # TODO FP precision error # Failed (TODO) test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 ok 1 - test_add 1..1 ok 1 - TestsFor.Adder # Running tests for TestsFor.Subtractor # # Subtest: TestsFor.Subtractor # TestsFor.Subtractor.test_subtract() # Subtest: test_subtract ok 1-1 minus 1 equals 0 ok 2-0 minus -100 equals 100 1..2 ok 1 - test_subtract 1..1 ok 2 - TestsFor.Subtractor!94

# Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # TODO FP precision error # Failed (TODO) test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 ok 1 - test_add 1..1 ok 1 - TestsFor.Adder # Running tests for TestsFor.Subtractor # # Subtest: TestsFor.Subtractor # TestsFor.Subtractor.test_subtract() # Subtest: test_subtract ok 1-1 minus 1 equals 0 ok 2-0 minus -100 equals 100 1..2 ok 1 - test_subtract 1..1 ok 2 - TestsFor.Subtractor!95

# Running tests for TestsFor.Adder # # Subtest: TestsFor.Adder # TestsFor.Adder.test_add() # Subtest: test_add ok 1-2.0001 plus 1.9999 equals 4 not ok 2-1e100 plus 2e100 equals 3e100 # TODO FP precision error # Failed (TODO) test (t/tests/testsfor/adder.lua at line 9) # got: 3e+100 # expected: 3e+100 1..2 ok 1 - test_add 1..1 ok 1 - TestsFor.Adder # Running tests for TestsFor.Subtractor # # Subtest: TestsFor.Subtractor # TestsFor.Subtractor.test_subtract() # Subtest: test_subtract ok 1-1 minus 1 equals 0 ok 2-0 minus -100 equals 100 1..2 ok 1 - test_subtract 1..1 ok 2 - TestsFor.Subtractor!96

Как загрузить много тестовых классов?!97

t/tc.lua require('testsfor.adder') require('testsfor.subtractor') require('testsfor.multiplier') require('testsfor.divider') require('testsfor.utils') require('testsfor.context') require('testsfor.character') require('testsfor.station') require('testsfor.travel') --... local tc = require('test.class') tc.run_tests()!98

t/tc-load.lua local tc = require('test.class') tc.load_classes('t/tests') tc.run_tests()!99

load_classes(dir) Рекурсивно обходит указанную директорию в поисках.lua файлов Для каждого найденного файла: Преобразует имя файла в имя модуля Загружает его при помощи require() Если это наследник Test.Class - добавляет в список для запуска!100

t/tc-load.lua local tc = require('test.class') tc.load_classes('t/tests') tc.run_tests()!101

run_tests(arg) Для каждого тестового класса из списка: создает объект при помощи new()......и запускает на нем тестовые методы arg - таблица с опциональным параметром: include - регулярное выражение, ограничивающее методы для запуска!102

Подготовка / очистка тестовых данных!103

...для тестового класса test_startup() - подготовка test_shutdown() - очистка!104

...для тестового метода test_setup() - подготовка self.current_method - имя метода test_teardown() - очистка!105

Наследование!106

Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом. Принцип подстановки Барбары Лисков (определение Роберта С. Мартина)!107

local _M = require('middleclass')('testsfor.parent', require('test.class')) require 'Test.More' function _M:test_parent() end pass('i am a test of parent') return _M!108

local _M = require('middleclass')('testsfor.parent', require('test.class')) require 'Test.More' function _M:test_parent() end pass('i am a test of parent') return _M!109

local _M = require('middleclass')('testsfor.parent', require('test.class')) require 'Test.More' function _M:test_parent() end pass('i am a test of parent') return _M!110

local _M = require('middleclass')('testsfor.parent', require('test.class')) require 'Test.More' function _M:test_parent() end pass('i am a test of parent') return _M!111

local _M = require('middleclass')('testsfor.child', require('testsfor.parent')) require 'Test.More' function _M:test_child() end pass('i am a test of child') return _M!112

local _M = require('middleclass')('testsfor.child', require('testsfor.parent')) require 'Test.More' function _M:test_child() end pass('i am a test of child') return _M!113

local _M = require('middleclass')('testsfor.child', require('testsfor.parent')) require 'Test.More' function _M:test_child() end pass('i am a test of child') return _M!114

t/tc-inheritance.lua.. # Running tests for TestsFor.Parent # # Subtest: TestsFor.Parent # TestsFor.Parent.test_parent() # Subtest: test_parent ok 1 - I am a test of parent 1..1 ok 1 - test_parent 1..1 ok 1 - TestsFor.Parent # Running tests for TestsFor.Child #...!115

# Running tests for TestsFor.Child # # Subtest: TestsFor.Child # TestsFor.Child.test_child() # Subtest: test_child ok 1 - I am a test of child 1..1 ok 1 - test_child # TestsFor.Child.test_parent() # Subtest: test_parent ok 1 - I am a test of parent 1..1 ok 2 - test_parent 1..2 ok 2 - TestsFor.Child 1..2 ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS!116

Mixins!117

lib/mytestmixin.lua require 'Test.More' return { pi = 3.1415, } test_from_mixin = function() end pass('this test always passes')!118

t/tests/testsfor/mixin.lua local _M = require('middleclass')('testsfor.mixin', require('test.class')) :include(require('mytestmixin')) function _M:test_pi() end pass('pi is: '.. self.pi) return _M!119

t/tests/testsfor/mixin.lua local _M = require('middleclass')('testsfor.mixin', require('test.class')) :include(require('mytestmixin')) function _M:test_pi() end pass('pi is: '.. self.pi) return _M!120

t/tests/testsfor/mixin.lua local _M = require('middleclass')('testsfor.mixin', require('test.class')) :include(require('mytestmixin')) function _M:test_pi() end pass('pi is: '.. self.pi) return _M!121

t/tc-mixin.lua.. # Running tests for TestsFor.Mixin # # Subtest: TestsFor.Mixin # TestsFor.Mixin.test_from_mixin() # Subtest: test_from_mixin ok 1 - This test always passes 1..1 ok 1 - test_from_mixin # TestsFor.Mixin.test_pi() # Subtest: test_pi ok 1 - PI is: 3.1415 1..1 ok 2 - test_pi 1..2 ok 1 - TestsFor.Mixin 1..1 ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS!122

t/tc-mixin.lua.. # Running tests for TestsFor.Mixin # # Subtest: TestsFor.Mixin # TestsFor.Mixin.test_from_mixin() # Subtest: test_from_mixin ok 1 - This test always passes 1..1 ok 1 - test_from_mixin # TestsFor.Mixin.test_pi() # Subtest: test_pi ok 1 - PI is: 3.1415 1..1 ok 2 - test_pi 1..2 ok 1 - TestsFor.Mixin 1..1 ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS!123

t/tc-mixin.lua.. # Running tests for TestsFor.Mixin # # Subtest: TestsFor.Mixin # TestsFor.Mixin.test_from_mixin() # Subtest: test_from_mixin ok 1 - This test always passes 1..1 ok 1 - test_from_mixin # TestsFor.Mixin.test_pi() # Subtest: test_pi ok 1 - PI is: 3.1415 1..1 ok 2 - test_pi 1..2 ok 1 - TestsFor.Mixin 1..1 ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS!124

Ок, с Test.Class мы можем...!125

С Test.Class мы можем Написать юнит-тест Запустить тесты: Для выбранных или для всех классов в директории Для всех или выбранных методов Подготавливать / очищать данные для тестов Использовать наследование и примеси!126

Лаконичные assert-ы Структуризация Наследование Подготовка/ очистка данных Выборочный запуск Test.More Busted LuaUnit Test.Class!127

Test.Class - особенности Работает только на *nix-based системах (сейчас) Нет тестов, документации Ранняя альфа версия - возможны (и наверняка будут) изменения!128

Использовать на свой страх и риск ;-)!129

Test.Class - wishlist / plans Поддержка тестового плана "Автоплан" по количеству тестовых классов / методов Пропуск тестовых классов / методов Меньше boilerplate в начале тестовых классов!130

Скачать (бесплатно, без sms) Busted: luarocks.org LuaUnit: luarocks.org lua-testmore: luarocks.org github.com/ichesnokov/lua-testclass!131

Вопросы?!132

Спасибо!