Unit testing for Perl

                                                      Alexey Shrub

                                                Российские интернет-технологии


                                                       2011-04-26




Alexey Shrub, Российские интернет-технологии                           Unit testing for Perl   1/30
Модульное тестирование




             Автоматизированное.
             Изолированное.




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   2/30
Зачем нужны модульные тесты

             Необходимая верификация (+ двойная запись).




Alexey Shrub, Российские интернет-технологии     Unit testing for Perl   3/30
Зачем нужны модульные тесты

             Необходимая верификация (+ двойная запись).
             Борьба с ростом энтропии (регрессом) при изменениях (= легкость
             рефакторинга).




Alexey Shrub, Российские интернет-технологии      Unit testing for Perl        3/30
Зачем нужны модульные тесты

             Необходимая верификация (+ двойная запись).
             Борьба с ростом энтропии (регрессом) при изменениях (= легкость
             рефакторинга).
             Локализация ошибок (в отличие от интеграционных).




Alexey Shrub, Российские интернет-технологии      Unit testing for Perl        3/30
Зачем нужны модульные тесты

             Необходимая верификация (+ двойная запись).
             Борьба с ростом энтропии (регрессом) при изменениях (= легкость
             рефакторинга).
             Локализация ошибок (в отличие от интеграционных).
             Раннее обнаружение ошибок (чем раньше, тем дешевле исправление
             ошибки).




Alexey Shrub, Российские интернет-технологии      Unit testing for Perl        3/30
Зачем нужны модульные тесты

             Необходимая верификация (+ двойная запись).
             Борьба с ростом энтропии (регрессом) при изменениях (= легкость
             рефакторинга).
             Локализация ошибок (в отличие от интеграционных).
             Раннее обнаружение ошибок (чем раньше, тем дешевле исправление
             ошибки).
             Раннее обнаружение неудобного интерфейса.




Alexey Shrub, Российские интернет-технологии      Unit testing for Perl        3/30
Зачем нужны модульные тесты

             Необходимая верификация (+ двойная запись).
             Борьба с ростом энтропии (регрессом) при изменениях (= легкость
             рефакторинга).
             Локализация ошибок (в отличие от интеграционных).
             Раннее обнаружение ошибок (чем раньше, тем дешевле исправление
             ошибки).
             Раннее обнаружение неудобного интерфейса.
             Документация.



Alexey Shrub, Российские интернет-технологии      Unit testing for Perl        3/30
Стандартные отмазки нежелающих писать тесты



             Нет времени.
             Код нетестируемый.
             Не умею и боюсь, у меня и без тестов вроде/должно работать.




Alexey Shrub, Российские интернет-технологии      Unit testing for Perl    4/30
Тесты в Perl. Функциональное тестирование




Alexey Shrub, Российские интернет-технологии                Unit testing for Perl   5/30
use Test::More;

     Базовые функции
             ok
             is
             new_ok
             is_deeply
             ...
     Диагностика (diag/explain):
      i s _ d e e p l y ( $got , $ e x p e c t e d , ’ R e s u l t must be . . . ’ )
             or diag e x p l a i n $got ;



Alexey Shrub, Российские интернет-технологии             Unit testing for Perl         6/30
Минимальный пример
     Пример положительного функционального теста
     #! / u s r / b i n / p e r l −w
     use s t r i c t ;
     use T e s t : : More t e s t s => 1 ;
     use E m a i l : : V a l i d ;

     my $ e m a i l       = ’ w o r l d . mind@yahoo . com ’ ;
     my $ e x p e c t e d = $ e m a i l ;
     my $ g o t           = E m a i l : : V a l i d −>a d d r e s s ( $ e m a i l ) ;

      i s ( $got , $ e x p e c t e d , " $ e m a i l must be v a l i d " ) ;


Alexey Shrub, Российские интернет-технологии                 Unit testing for Perl      7/30
Запуск одного теста


     TAP - Test Anything Protocol
     Run test
     $ perl t/simple-test.t
     1..1
     ok 1 - world.mind@yahoo.com must be valid




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   8/30
Запуск набора тестов

     Run tests with Test:Harness
     $ prove
     t/simple-test.t .. ok
     t/use.t .......... ok
     All tests successful.
     Files=2, Tests=2, 1 wallclock secs ( 0.02 usr                     0.01 sys +   0.14 cusr
     Result: PASS

     Makefile - бывает удобнее



Alexey Shrub, Российские интернет-технологии   Unit testing for Perl                     9/30
Тестирование исключений
     Test::Exception
     #! / u s r / b i n / p e r l −w
     use s t r i c t ;
     use F a t a l qw( open c l o s e ) ;
     use T e s t : : More t e s t s => 1 ;
     use T e s t : : E x c e p t i o n ;

     my $ f i l e n a m e = ’ t h e _ n o t _ e x i s t e d _ f i l e ’ ;

      throws_ok { open (my $fh , "<" , $ f i l e n a m e ) }
          q r /No s u c h f i l e / ,
           ’ open ( ) w i t h bad f i l e name must throw e x c e p t i o n ’ ;

Alexey Shrub, Российские интернет-технологии                   Unit testing for Perl   10/30
Генерация входных данных
     Test::LectroTest::Compat
     #! / u s r / b i n / p e r l −w

     use s t r i c t ;
     use T e s t : : More t e s t s => 1 ;
     use T e s t : : L e c t r o T e s t : : Compat ;

     my $ p r o p _ n o n n e g a t i v e = P r o p e r t y {
          ##[ x <− I n t ]##
          cmp_ok ( abs ( $x ) , ’>= ’ , 0 ) ;
     } , name => " a b s o u t p u t must be non− n e g a t i v e " ;

      holds ( $prop_nonnegative ) ;
Alexey Shrub, Российские интернет-технологии            Unit testing for Perl   11/30
Что делать, если модуль взаимодействует с внешним миром?


             Пишет/читает базу.
             Обращается к web страницам/скриптам.
             Пишет/читает memcache.
             Вызывает SOAP/XML-RPC сервисы.
             и т.п.


                                               ?


Alexey Shrub, Российские интернет-технологии       Unit testing for Perl   12/30
Mock/Stub/Fake

     Mock модули общего назначения
             Test::MockObject
             Test::MockModule
        Test::MockClass
     Специализированные
             DBD::Mock
             Test::Mock::LWP
             Cache::Memcached::Mock
             и т.п.


Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   13/30
Пример подмены модуля LWP I
     #! / u s r / b i n / p e r l −w
     use s t r i c t ;
     use T e s t : : More t e s t s => 3 ;
     use T e s t : : MockObject ;
     use Cache : : Memcached : : F a s t ;
     use l i b qw( l i b ) ;

     my      $server               =     ’ l o c a l h o s t :11211 ’ ;
     my      $key                  =     ’ mykey ’ ;
     my      $value                =     ’ value ’ ;
     my      $newvalue             =     ’ newvalue ’ ;

     BEGIN {
Alexey Shrub, Российские интернет-технологии                          Unit testing for Perl   14/30
Пример подмены модуля LWP II
          $_ = ’ MyMemcacheWrapper ’ ;
          use_ok ( $_ ) ;
     }

     # moking Cache : : Memcached : : F a s t
     my $memc_mock = T e s t : : MockObject −>new ( ) ;
     T e s t : : MockObject −>fake_module ( ’ Cache : : Memcached : : F a s t ’ ,
            new => sub { $memc_mock } ) ;

     my $memcache = {
         $key , $ v a l u e ,
     };


Alexey Shrub, Российские интернет-технологии     Unit testing for Perl              15/30
Пример подмены модуля LWP III
     $memc_mock−>mock (
         ’ get ’ ,
         sub {
              my ( $ s e l f , $ ke y ) = @_;
               return $memcache −>{$ ke y } ;
         }
     );

     $memc_mock−>mock (
         ’ set ’ ,
         sub {
              my ( $ s e l f , $key , $ v a l u e ) = @_;
               $memcache −>{$ ke y } = $ v a l u e ;

Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   16/30
Пример подмены модуля LWP IV
               }
      );

     # g e t o u r w r a p p e r o b j e c t and memcached c o n n e c t i o n
     my $mem_wrap = new_ok ( $_ , [ s e r v e r => $ s e r v e r ] ) ;
     my $memcached = new Cache : : Memcached : : F a s t (
          { s e r v e r s => [ { a d d r e s s => $ s e r v e r } , ] , } ) ;

     # check s e t
     $mem_wrap−>s e t _ v a l u e ( $key , $ n e w v a l u e ) ;
     i s ( $memcached−>g e t ( $ key ) , $n e w v a l u e ,
           ’ s e t _ v a l u e must s e t v a l u e i n memcache ’ ) ;


Alexey Shrub, Российские интернет-технологии        Unit testing for Perl        17/30
Нефункциональное тестирование
                                           Автоматизированный code review
                                                     Почему?
                                                      Зачем?




Alexey Shrub, Российские интернет-технологии                   Unit testing for Perl   18/30
Компилируется?

             Test::Strict

     #! / u s r / b i n / p e r l −w
     use s t r i c t ;
     use w a r n i n g s ;
     use T e s t : : More ;
     use T e s t : : S t r i c t ;

      a l l _ p e r l _ f i l e s _ o k ( qw/ l i b t x t / ) ;




Alexey Shrub, Российские интернет-технологии              Unit testing for Perl   19/30
Соответствует соглашению о стиле кодирования?



             Test::EOL
             Test::NoTabs
             Test::PerlTidy




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   20/30
Используются ли рекомендации из Perl Best Practice




             Test::Perl::Critic
             Test::Portability::Files




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   21/30
Не забыли ли чего? (инструменты в больном)




             Test::Fixme
             Test::NoBreakpoints




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   22/30
Метрики в норме?




             Perl::Metrics::Simple




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   23/30
Есть ли документация?



             Test::Pod
             Test::Pod::Coverage
             Test::Spelling




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   24/30
Есть ли нужное количество тестов?




             Test::Strict (Devel::Cover)




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   25/30
Не стал ли код медленнее?




             Test::Timer




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   26/30
Нет ли утечек памяти?




             Test::Weaken




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl   27/30
О чём говорит успешное прохождение таких тестов?

             Код компилируется! Это уже успех!
             Стиль кодирования соответствует заданному!
             Выполняются хотя бы минимальные рекомендации из PBP!
             Доделано всё, о чем были пометки!
             Метрики сложности дают надежду на то, что код можно понять!
             Была попытка написать документацию ко всем методам!
             Есть тесты! И их количество соответствует запланированному!
             Код ещё не самый тормозной!
             Можно надеяться на то, что память не течёт!


Alexey Shrub, Российские интернет-технологии      Unit testing for Perl    28/30
Максимальный набор, все кроме последних двух не зависят от кода, можно
     копипастить и запускать




Alexey Shrub, Российские интернет-технологии   Unit testing for Perl          29/30
Вопросы


                                               QUESTIONS?
     Исходники презентации (LaTeX, Beamer):
     https://github.com/worldmind/perl-unit-testing-presentation-ru.git

     Набор тестов:
     https://github.com/worldmind/perl-test-code-quality-template.git

     Feedback to:
     ashrub@yandex.ru


Alexey Shrub, Российские интернет-технологии          Unit testing for Perl   30/30

модульное тестирование для Perl. алексей шруб. зал 4

  • 1.
    Unit testing forPerl Alexey Shrub Российские интернет-технологии 2011-04-26 Alexey Shrub, Российские интернет-технологии Unit testing for Perl 1/30
  • 2.
    Модульное тестирование Автоматизированное. Изолированное. Alexey Shrub, Российские интернет-технологии Unit testing for Perl 2/30
  • 3.
    Зачем нужны модульныетесты Необходимая верификация (+ двойная запись). Alexey Shrub, Российские интернет-технологии Unit testing for Perl 3/30
  • 4.
    Зачем нужны модульныетесты Необходимая верификация (+ двойная запись). Борьба с ростом энтропии (регрессом) при изменениях (= легкость рефакторинга). Alexey Shrub, Российские интернет-технологии Unit testing for Perl 3/30
  • 5.
    Зачем нужны модульныетесты Необходимая верификация (+ двойная запись). Борьба с ростом энтропии (регрессом) при изменениях (= легкость рефакторинга). Локализация ошибок (в отличие от интеграционных). Alexey Shrub, Российские интернет-технологии Unit testing for Perl 3/30
  • 6.
    Зачем нужны модульныетесты Необходимая верификация (+ двойная запись). Борьба с ростом энтропии (регрессом) при изменениях (= легкость рефакторинга). Локализация ошибок (в отличие от интеграционных). Раннее обнаружение ошибок (чем раньше, тем дешевле исправление ошибки). Alexey Shrub, Российские интернет-технологии Unit testing for Perl 3/30
  • 7.
    Зачем нужны модульныетесты Необходимая верификация (+ двойная запись). Борьба с ростом энтропии (регрессом) при изменениях (= легкость рефакторинга). Локализация ошибок (в отличие от интеграционных). Раннее обнаружение ошибок (чем раньше, тем дешевле исправление ошибки). Раннее обнаружение неудобного интерфейса. Alexey Shrub, Российские интернет-технологии Unit testing for Perl 3/30
  • 8.
    Зачем нужны модульныетесты Необходимая верификация (+ двойная запись). Борьба с ростом энтропии (регрессом) при изменениях (= легкость рефакторинга). Локализация ошибок (в отличие от интеграционных). Раннее обнаружение ошибок (чем раньше, тем дешевле исправление ошибки). Раннее обнаружение неудобного интерфейса. Документация. Alexey Shrub, Российские интернет-технологии Unit testing for Perl 3/30
  • 9.
    Стандартные отмазки нежелающихписать тесты Нет времени. Код нетестируемый. Не умею и боюсь, у меня и без тестов вроде/должно работать. Alexey Shrub, Российские интернет-технологии Unit testing for Perl 4/30
  • 10.
    Тесты в Perl.Функциональное тестирование Alexey Shrub, Российские интернет-технологии Unit testing for Perl 5/30
  • 11.
    use Test::More; Базовые функции ok is new_ok is_deeply ... Диагностика (diag/explain): i s _ d e e p l y ( $got , $ e x p e c t e d , ’ R e s u l t must be . . . ’ ) or diag e x p l a i n $got ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 6/30
  • 12.
    Минимальный пример Пример положительного функционального теста #! / u s r / b i n / p e r l −w use s t r i c t ; use T e s t : : More t e s t s => 1 ; use E m a i l : : V a l i d ; my $ e m a i l = ’ w o r l d . mind@yahoo . com ’ ; my $ e x p e c t e d = $ e m a i l ; my $ g o t = E m a i l : : V a l i d −>a d d r e s s ( $ e m a i l ) ; i s ( $got , $ e x p e c t e d , " $ e m a i l must be v a l i d " ) ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 7/30
  • 13.
    Запуск одного теста TAP - Test Anything Protocol Run test $ perl t/simple-test.t 1..1 ok 1 - world.mind@yahoo.com must be valid Alexey Shrub, Российские интернет-технологии Unit testing for Perl 8/30
  • 14.
    Запуск набора тестов Run tests with Test:Harness $ prove t/simple-test.t .. ok t/use.t .......... ok All tests successful. Files=2, Tests=2, 1 wallclock secs ( 0.02 usr 0.01 sys + 0.14 cusr Result: PASS Makefile - бывает удобнее Alexey Shrub, Российские интернет-технологии Unit testing for Perl 9/30
  • 15.
    Тестирование исключений Test::Exception #! / u s r / b i n / p e r l −w use s t r i c t ; use F a t a l qw( open c l o s e ) ; use T e s t : : More t e s t s => 1 ; use T e s t : : E x c e p t i o n ; my $ f i l e n a m e = ’ t h e _ n o t _ e x i s t e d _ f i l e ’ ; throws_ok { open (my $fh , "<" , $ f i l e n a m e ) } q r /No s u c h f i l e / , ’ open ( ) w i t h bad f i l e name must throw e x c e p t i o n ’ ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 10/30
  • 16.
    Генерация входных данных Test::LectroTest::Compat #! / u s r / b i n / p e r l −w use s t r i c t ; use T e s t : : More t e s t s => 1 ; use T e s t : : L e c t r o T e s t : : Compat ; my $ p r o p _ n o n n e g a t i v e = P r o p e r t y { ##[ x <− I n t ]## cmp_ok ( abs ( $x ) , ’>= ’ , 0 ) ; } , name => " a b s o u t p u t must be non− n e g a t i v e " ; holds ( $prop_nonnegative ) ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 11/30
  • 17.
    Что делать, еслимодуль взаимодействует с внешним миром? Пишет/читает базу. Обращается к web страницам/скриптам. Пишет/читает memcache. Вызывает SOAP/XML-RPC сервисы. и т.п. ? Alexey Shrub, Российские интернет-технологии Unit testing for Perl 12/30
  • 18.
    Mock/Stub/Fake Mock модули общего назначения Test::MockObject Test::MockModule Test::MockClass Специализированные DBD::Mock Test::Mock::LWP Cache::Memcached::Mock и т.п. Alexey Shrub, Российские интернет-технологии Unit testing for Perl 13/30
  • 19.
    Пример подмены модуляLWP I #! / u s r / b i n / p e r l −w use s t r i c t ; use T e s t : : More t e s t s => 3 ; use T e s t : : MockObject ; use Cache : : Memcached : : F a s t ; use l i b qw( l i b ) ; my $server = ’ l o c a l h o s t :11211 ’ ; my $key = ’ mykey ’ ; my $value = ’ value ’ ; my $newvalue = ’ newvalue ’ ; BEGIN { Alexey Shrub, Российские интернет-технологии Unit testing for Perl 14/30
  • 20.
    Пример подмены модуляLWP II $_ = ’ MyMemcacheWrapper ’ ; use_ok ( $_ ) ; } # moking Cache : : Memcached : : F a s t my $memc_mock = T e s t : : MockObject −>new ( ) ; T e s t : : MockObject −>fake_module ( ’ Cache : : Memcached : : F a s t ’ , new => sub { $memc_mock } ) ; my $memcache = { $key , $ v a l u e , }; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 15/30
  • 21.
    Пример подмены модуляLWP III $memc_mock−>mock ( ’ get ’ , sub { my ( $ s e l f , $ ke y ) = @_; return $memcache −>{$ ke y } ; } ); $memc_mock−>mock ( ’ set ’ , sub { my ( $ s e l f , $key , $ v a l u e ) = @_; $memcache −>{$ ke y } = $ v a l u e ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 16/30
  • 22.
    Пример подмены модуляLWP IV } ); # g e t o u r w r a p p e r o b j e c t and memcached c o n n e c t i o n my $mem_wrap = new_ok ( $_ , [ s e r v e r => $ s e r v e r ] ) ; my $memcached = new Cache : : Memcached : : F a s t ( { s e r v e r s => [ { a d d r e s s => $ s e r v e r } , ] , } ) ; # check s e t $mem_wrap−>s e t _ v a l u e ( $key , $ n e w v a l u e ) ; i s ( $memcached−>g e t ( $ key ) , $n e w v a l u e , ’ s e t _ v a l u e must s e t v a l u e i n memcache ’ ) ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 17/30
  • 23.
    Нефункциональное тестирование Автоматизированный code review Почему? Зачем? Alexey Shrub, Российские интернет-технологии Unit testing for Perl 18/30
  • 24.
    Компилируется? Test::Strict #! / u s r / b i n / p e r l −w use s t r i c t ; use w a r n i n g s ; use T e s t : : More ; use T e s t : : S t r i c t ; a l l _ p e r l _ f i l e s _ o k ( qw/ l i b t x t / ) ; Alexey Shrub, Российские интернет-технологии Unit testing for Perl 19/30
  • 25.
    Соответствует соглашению остиле кодирования? Test::EOL Test::NoTabs Test::PerlTidy Alexey Shrub, Российские интернет-технологии Unit testing for Perl 20/30
  • 26.
    Используются ли рекомендациииз Perl Best Practice Test::Perl::Critic Test::Portability::Files Alexey Shrub, Российские интернет-технологии Unit testing for Perl 21/30
  • 27.
    Не забыли личего? (инструменты в больном) Test::Fixme Test::NoBreakpoints Alexey Shrub, Российские интернет-технологии Unit testing for Perl 22/30
  • 28.
    Метрики в норме? Perl::Metrics::Simple Alexey Shrub, Российские интернет-технологии Unit testing for Perl 23/30
  • 29.
    Есть ли документация? Test::Pod Test::Pod::Coverage Test::Spelling Alexey Shrub, Российские интернет-технологии Unit testing for Perl 24/30
  • 30.
    Есть ли нужноеколичество тестов? Test::Strict (Devel::Cover) Alexey Shrub, Российские интернет-технологии Unit testing for Perl 25/30
  • 31.
    Не стал ликод медленнее? Test::Timer Alexey Shrub, Российские интернет-технологии Unit testing for Perl 26/30
  • 32.
    Нет ли утечекпамяти? Test::Weaken Alexey Shrub, Российские интернет-технологии Unit testing for Perl 27/30
  • 33.
    О чём говоритуспешное прохождение таких тестов? Код компилируется! Это уже успех! Стиль кодирования соответствует заданному! Выполняются хотя бы минимальные рекомендации из PBP! Доделано всё, о чем были пометки! Метрики сложности дают надежду на то, что код можно понять! Была попытка написать документацию ко всем методам! Есть тесты! И их количество соответствует запланированному! Код ещё не самый тормозной! Можно надеяться на то, что память не течёт! Alexey Shrub, Российские интернет-технологии Unit testing for Perl 28/30
  • 34.
    Максимальный набор, всекроме последних двух не зависят от кода, можно копипастить и запускать Alexey Shrub, Российские интернет-технологии Unit testing for Perl 29/30
  • 35.
    Вопросы QUESTIONS? Исходники презентации (LaTeX, Beamer): https://github.com/worldmind/perl-unit-testing-presentation-ru.git Набор тестов: https://github.com/worldmind/perl-test-code-quality-template.git Feedback to: ashrub@yandex.ru Alexey Shrub, Российские интернет-технологии Unit testing for Perl 30/30