«Автотесты» Вадим Пуштаев, программист отдела...
TRANSCRIPT
MR::Go::Admin::Test
Go::Admin
Go
Go::Admin
Go
Go
Go
Go Go Go
Go
Go
GoGo
xUnit
xUnit
SUnit
xUnit
SUnitJUnit
xUnit
SUnitJUnitunittest
xUnit
SUnitJUnitunittestrunit
xUnit
SUnitJUnitunittestrunitrspec
xUnit
SUnitJUnitunittestrunitrspecTest::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 → deletedelete → delete__already_deleted_delete → delete
delete → test_deletedelete → 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');}
Тестированиеприватныхметодов
Структуратеста
Структуратеста
ArrangeActAssert
Структуратеста
ArrangeActAssert
SetupExerciseVerifyTeardown
База
БазаПоддельная база
БазаПоддельная база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 = BEGINteardown = ROLLBACK
Транзакцииsetup = BEGINteardown = ROLLBACK$self->break_db();
Testdoubles
Testdoubles
Mock
Testdoubles
MockSpy
Testdoubles
MockSpyStub
Testdoubles
MockSpyStubDummy
Моки с магией
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';
Assertsis($node->children->count, 0, 'leaf node');
Assertsis($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
Бонус: ExportCatcher
{ package MR:Go::Admin::Test::_ExportCatcher;
use MR::Go::Admin::Schema; use Test::DBIx::Class;}