Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
MR::Go::Admin::Test
Search
Vadim Pushtaev
January 23, 2017
Programming
0
76
MR::Go::Admin::Test
Vadim Pushtaev
January 23, 2017
Tweet
Share
More Decks by Vadim Pushtaev
See All by Vadim Pushtaev
PyCon Russia 2018 — Unit Testing
vadimpushtaev
0
390
Perl course (5), testing
vadimpushtaev
0
99
Perl course (4), testing
vadimpushtaev
0
100
Perl course (4), db
vadimpushtaev
0
210
Perl course (4), oop
vadimpushtaev
1
180
Perl course (4), mod
vadimpushtaev
0
200
Perl course (3), testing
vadimpushtaev
0
88
Perl course (3), db
vadimpushtaev
0
79
Perl course (3), oop
vadimpushtaev
0
97
Other Decks in Programming
See All in Programming
ソフトウェア設計とAI技術の活用
masuda220
PRO
25
7k
型で語るカタ
irof
1
880
副作用と戦う PHP リファクタリング ─ ドメインイベントでビジネスロジックを解きほぐす
kajitack
3
490
中級グラフィックス入門~効率的なメッシュレット描画~
projectasura
3
2k
Jakarta EE Meets AI
ivargrimstad
0
450
それ CLI フレームワークがなくてもできるよ / Building CLI Tools Without Frameworks
orgachem
PRO
13
3.3k
The Evolution of Enterprise Java with Jakarta EE 11 and Beyond
ivargrimstad
0
590
No Install CMS戦略 〜 5年先を見据えたフロントエンド開発を考える / no_install_cms
rdlabo
0
390
MCPで実現できる、Webサービス利用体験について
syumai
7
2.2k
なぜあなたのオブザーバビリティ導入は頓挫するのか
ryota_hnk
4
520
The Modern View Layer Rails Deserves: A Vision For 2025 And Beyond @ RailsConf 2025, Philadelphia, PA
marcoroth
2
830
リッチエディターを安全に開発・運用するために
unachang113
1
310
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
2.7k
Adopting Sorbet at Scale
ufuk
77
9.5k
Agile that works and the tools we love
rasmusluckow
329
21k
Documentation Writing (for coders)
carmenintech
72
4.9k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
47
9.6k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
1k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.5k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
Why Our Code Smells
bkeepers
PRO
337
57k
Art, The Web, and Tiny UX
lynnandtonic
301
21k
Transcript
MR::Go::Admin::Test
Go::Admin Go
Go::Admin Go Go Go Go Go Go Go Go Go
Go
xUnit
xUnit SUnit
xUnit SUnit JUnit
xUnit SUnit JUnit unittest
xUnit SUnit JUnit unittest runit
xUnit SUnit JUnit unittest runit rspec
xUnit SUnit JUnit unittest runit rspec Test::Class
xUnit Test Patterns Автор: Месарош Джерард
package MR::Go::Admin::User::Test; sub setup : Test(setup) { my ($self) =
@_; $self->{user} = create_user(); } sub test_delete : Test(2) { my ($self) = @_; $self->{user}->delete(); # ... } Test::Class
Именование классов MR::Go::Admin::User → MR::Go::Admin::User::Test
Именование классов MR::Go::Admin::User → MR::Go::Admin::User::Test *::Test запрещены не в тестах
Именование классов MR::Go::Admin::User → MR::Go::Admin::User::Test *::Test запрещены не в тестах
MR::Go::Admin::User::Test::_FakeUser
Именование методов delete → delete delete → delete__already_deleted _delete →
delete delete → test_delete delete → test_delete__already_deleted _delete → test__delete__already_deleted Двойное подчеркивание
https://goo.gl/tBIRwZ sub _set_status { my ($self, $status) = @_; $self->_status($status);
$self->_history->add($status); $self->_log('...'); } sub set_status_processing { return shift->_set_status('processing'); } sub set_status_processed { return shift->_set_status('processing'); } Тестирование приватных методов
Структура теста
Структура теста Arrange Act Assert
Структура теста Arrange Act Assert Setup Exercise Verify Teardown
База
База Поддельная база
База Поддельная база SQLite
База Поддельная база SQLite Настоящая база
База Поддельная база SQLite Настоящая база Test::DBIx::Class
Fixtures
Fixtures Копия реальной базы
Fixtures Копия реальной базы Слепок реальной базы
Fixtures Копия реальной базы Слепок реальной базы Искусственно подготовленный слепок
Fixtures Копия реальной базы Слепок реальной базы Искусственно подготовленный слепок
Пустая база
Fixtures Копия реальной базы Слепок реальной базы Искусственно подготовленный слепок
Пустая база Фабрики
package MR::Go::Admin::UserFactory; use base qw(DBIx::Class::Factory); __PACKAGE__->resultset(MR::Go::Admin:: Schema->resultset('User')); __PACKAGE__->fields({ name =>
__PACKAGE__->seq(sub {'User #' . shift}), city => __PACKAGE__->related_factory('MR::Go::Admin::CityFactory'), status => 'new', }); DBIx::Class::Factory
package MR::Go::Admin::UserFactory; use base qw(DBIx::Class::Factory); __PACKAGE__->resultset(MR::Go::Admin:: Schema->resultset('User')); __PACKAGE__->fields({ name =>
__PACKAGE__->seq(sub {'User #' . shift}), city => __PACKAGE__->related_factory('MR::Go::Admin::CityFactory'), status => 'new', }); https://goo.gl/tBIRwZ DBIx::Class::Factory
Фабрика в деле sub set_status : Test(1) { my ($self)
= @_; my $task = MR::Admin::Go::Test::Factory::Task->create(); $task->set_status('TEST_NEW_STATUS'); is($task->status, 'TEST_NEW_STATUS', 'status'); return; }
Транзакции
Транзакции setup = BEGIN
Транзакции setup = BEGIN teardown = ROLLBACK
Транзакции setup = BEGIN teardown = ROLLBACK $self->break_db();
Test doubles
Test doubles Mock
Test doubles Mock Spy
Test doubles Mock Spy Stub
Test doubles Mock Spy Stub Dummy
Моки с магией my $mock = Test::MockModule->new('MR::Go::Admin::SMS'); my $sent =
0; $mock->mock(_send => sub { $sent = 1 });
Моки с магией local *MR::Go::Admin::SMS::_send = sub { $sent++ };
my $mock = Test::MockModule->new('MR::Go::Admin::SMS'); my $sent = 0; $mock->mock(_send => sub { $sent = 1 });
Моки без магии package MR::Go::Admin::User::Test::_FakeUser; MR::Go::Admin::User::Test::_FakeUser->new(); bless $user, 'MR::Go::Admin::User::Test::_FakeUser';
Моки без магии has _logger => (default => sub {
'...' }); User->new({_logger => $fake_logger}); User->new({_message_size_limit => 42}); package MR::Go::Admin::User::Test::_FakeUser; MR::Go::Admin::User::Test::_FakeUser->new(); bless $user, 'MR::Go::Admin::User::Test::_FakeUser';
Asserts is($node->children->count, 0, 'leaf node');
Asserts is($node->children->count, 0, 'leaf node'); is($rating, 42); cmp_ok($status, 'eq', 'processed');
ok($user->deleted);
is($node->children->count, 0, 'leaf node'); is($rating, 42); cmp_ok($status, 'eq', 'processed'); ok($user->deleted);
Asserts use Test::Deep;
cmp_deeply( $users, bag($user1, $user2) ); cmp_deeply( $user, methods( rating =>
42, blocked => bool(0), ) ); Test::Deep
Спасибо Вадим Пуштаев
[email protected]
https://goo.gl/SNrhWp Дизайн Максим Гелета
Бонус: ExportCatcher { package MR:Go::Admin::Test::_ExportCatcher; use MR::Go::Admin::Schema; use Test::DBIx::Class; }