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
100
Perl course (4), testing
vadimpushtaev
0
110
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
90
Perl course (3), db
vadimpushtaev
0
79
Perl course (3), oop
vadimpushtaev
0
98
Other Decks in Programming
See All in Programming
為你自己學 Python - 冷知識篇
eddie
1
220
🔨 小さなビルドシステムを作る
momeemt
2
560
DockerからECSへ 〜 AWSの海に出る前に知っておきたいこと 〜
ota1022
5
1.8k
AI時代のドメイン駆動設計-DDD実践におけるAI活用のあり方 / ddd-in-ai-era
minodriven
23
9k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
200
フロントエンドのmonorepo化と責務分離のリアーキテクト
kajitack
2
140
Rancher と Terraform
fufuhu
0
110
The State of Fluid (2025)
s2b
0
200
令和最新版手のひらコンピュータ
koba789
14
8k
AHC051解法紹介
eijirou
0
630
技術的負債で信頼性が限界だったWordPress運用をShifterで完全復活させた話
rvirus0817
1
2.2k
RDoc meets YARD
okuramasafumi
3
140
Featured
See All Featured
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
[RailsConf 2023] Rails as a piece of cake
palkan
56
5.8k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
21k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Writing Fast Ruby
sferik
628
62k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
How to train your dragon (web standard)
notwaldorf
96
6.2k
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; }