新時代のテストフレームワークTest2

7a8922191c1fa60728589a3def4c179f?s=47 akiym
July 01, 2017

 新時代のテストフレームワークTest2

YAPC::Fukuoka 2017 HAKATA

7a8922191c1fa60728589a3def4c179f?s=128

akiym

July 01, 2017
Tweet

Transcript

  1. ৽࣌୅ͷ ςετϑϨʔϜϫʔΫ 5FTU BLJZN :"1$'VLVPLB)","5"

  2. BLJZN

  3. ΞδΣϯμ w 1FSMͰςετΛॻ͘ w 5FTUͷ঺հ w 5FTUҠߦͷ஫ҙ఺ w 5FTUͰςετΛॻ͘ w

    ςετศར৘ใ
  4. 1FSMͰ ςετΛॻ͘

  5. 5FTU.PSF JT MJLF JT@EFFQMZ TVCUFTU  EPOF@UFTUJOH

  6. w JT஋ͷνΣοΫ w MJLFਖ਼نදݱύλʔϯʹϚον͢Δ͔ w JT@EFFQMZσʔλߏ଄ಉ࢜ͷൺֱ w 4,*1 50%0

  7. w ಺෦Ͱ͸5FTU#VJMEFSΛར༻ sub ok ($;$) { my( $test, $name )

    = @_; my $tb = Test::More->builder; return $tb->ok( $test, $name ); } 5FTU.PSFQN
  8. 5FTU%FFQ σΟʔϓͳൺֱ

  9. w σʔλߏ଄TFU CBH TVQFSIBTIPG w ΦϒδΣΫτͷϝιουͷνΣοΫ w ֦ுੑ͕ߴ͍5FTU%FFQ use Test::Deep;

    cmp_deeply [[1,3,2], {a => 1, b => 2, c => 3}], [set(1,2,3), superhashof({a => 1})]; ॱෆಉ LFZBͷνΣοΫɺ΄͔͸ແࢹ
  10. 5FTU'BUBM ྫ֎

  11. w ྫ֎͕ൃੜ͍ͨͯ͠͠ͳ͍νΣοΫ w ஥ؒ5FTU&YDFQUJPO use Test::Fatal; like exception { die

    "fatal" }, qr/fatal/; lives_ok { 'alive' };
  12. 5FTU.PDL(VBSE ͦͷείʔϓͷΈͰ ༗ޮͳϞοΫΛ࡞Δ

  13. use Test::Mock::Guard; my $g = mock_guard 'ExternalAPI', { fetch =>

    sub { 1 }, }; { my $g = mock_guard 'ExternalAPI', { fetch => sub { 0 }, }; ExternalAPI->fetch; #=> 0 } ExternalAPI->fetch; #=> 1 ͜ͷείʔϓ಺ͷΈͰ༗ޮ
  14. 5FTU8BSOJOHT ܯࠂ͕ग़͍ͯͳ͍͔ νΣοΫ

  15. w ಛఆͷείʔϓͰXBSOJOHΛัଊ w ҙਤ͠ͳ͍XBSOJOH͕ग़ͯͳ͍͔ use Test::Warnings; like warning { warn

    'test' }, qr/test/; warn 'debug'; done_testing; # fail!
  16. 5FTU$MBTT Y6OJUͬΆ͘ॻ͚Δ

  17. w TFUVQUFBSEPXO TUBSUVQTIVUEPXO w ؀ڥม਺5&45@.&5)0%Λࢦఆͯ͠ ಛఆͷςετͷΈ࣮ߦ

  18. package Foo; use parent qw/Test::Class/; sub setup : Test(setup) {

    $_[0]->{something} = 'init'; } sub foo : Tests { ... } sub bar : Tests { ... } __PACKAGE__->runtests; 5&45@.&5)0%GPPQSPWFUFTUU
  19. ςετ͸ศརͰ
 ͋Ε͹͋Δ΄Ͳخ͍͠

  20. ςετϑϨʔϜϫʔΫࣗମΛ ֦ுͨ͘͠ͳͬͯ͘Δ

  21. UUFTUQNʹ ॻ͔ΕͨศརϋοΫ

  22. ϞϯΩʔύον

  23. 5FTU#VJMEFSͷ֦ு͸େม

  24. 5FTUͷ
 ঺հ

  25. None
  26. 5FTU#VJMEFSΛஔ͖׵͑Δ ৽͍͠ςετϑϨʔϜϫʔΫ

  27. w 5FTU#VJMEFSΛϦϑΝΫλϦϯά w 5FTU4JNQMFEJTUSJCVUJPO
 όʔδϣϯҎ߱ w QFSM͔Β͸͕
 ඪ४Ϟδϡʔϧͱͯ͠ೖ͍ͬͯΔ

  28. ৽͍͠ͱ͸ w ςετͷςετ͕͠΍͍͢ w ֦ு͠΍͍͢ɺίʔυ͕੔ཧ͞Ε͍ͯΔ w Ҏલ͸5FTU#VJMEFSʹϞϯΩʔύον ͢Δ͔͠ͳ͔ͬͨ w ςετࣦഊ࣌ͷϨϙʔτ͕Θ͔Γ΍͍͢

  29. 5FTU#VJMEFSࣗମ͕ 5FTU"1*Ͱ
 ࣮૷͠௚͞Ε͍ͯΔ

  30. 5FTUҠߦͷ ஫ҙ఺

  31. جຊతʹ͸Ҏલͷ 5FTU#VJMEFSͱͷޓ׵ੑ͕ ҡ࣋͞Ε͍ͯΔ

  32. طଘͷςετ͕յΕΔ͔ʁ ˠେৎ෉

  33. ͨͩ͠5FTU#VJMEFSʹ ϞϯΩʔύον Λ͍ͯ͠ΔͱյΕΔ

  34. ؾ͍ͮͨΒ5FTUʹ
 ͳ͍ͬͯͨΒ

  35. $BSUPOͰόʔδϣϯ
 ݻఆ͍ͯ͠ͳ͍ ґଘϞδϡʔϧ͕5FTUʹґଘ

  36. None
  37. ٸʹςετ͕յΕΔલʹ 5FTUҠߦ͠·͠ΐ͏

  38. 5FTUҠߦͷ஫ҙ఺Λ঺հ

  39. ࣄྫ 

  40. VUGIBDLΛ΍ΊΔ

  41. use utf8; use Test::More; pass 'ਖ਼͍͠'; done_testing; Wide character in

    print at /.../Test2/Formatter/ TAP.pm line 113. ok 1 - ਖ਼͍͠ 1..1
  42. <VUGIBDL> 5FTU#VJMEFSʹϞϯΩʔύονͯ͠
 ग़ྗ࣌ʹVUGFODPEF

  43. binmode Test::More->builder->$_, ":utf8" for qw/output failure_output todo_output/; no warnings 'redefine';

    my $code = \&Test::Builder::child; *Test::Builder::child = sub { my $builder = $code->(@_); binmode $builder->$_, ":utf8" for qw/output failure_output todo_output/; return $builder; }; *__ORIGINAL::Test::Builder::_print_to_fh = \&Test::Builder::_print_to_fh; *Test::Builder::_print_to_fh = sub { my ($self, $fh, @args) = @_; binmode $fh, ':utf8'; goto \&__ORIGINAL::Test::Builder::_print_to_fh; }
  44. 5FTUͳΒ VTF5FTU1MVHJO65' ͢Δ͚ͩ

  45. use utf8; use Test::More; use Test2::Plugin::UTF8; pass 'ਖ਼͍͠'; done_testing; ࣮ࡍ͸UUFTUQN಺ʹॻ͍͓͍ͯͯ

    ςετϑΝΠϧຖʹVTFUUFTU͢Δͱ ศར
  46. ࣄྫ 

  47. &/%είʔϓ಺Ͱςετ͠ͳ͍

  48. 5FTU$MBTTͷSVOUFTUTΛ ࣗಈͰݺͿϋοΫ

  49. package t::test; sub import { my $pkg = caller; eval

    qq{ package $pkg; use parent qw/Test::Class/; use Test::More; END { $pkg->runtests; } }; } package Foo; use t::test; sub foo : Tests { fail; } # __PACKAGE__->runtests; # ෆཁ ऴྃ࣌ʹSVOUFTUT͕ݺ͹ΕΔ ςετ
  50. not ok 1 - foo # Failed test 'foo' #

    at /.../Test/Builder.pm line 135. # (in main->foo) 1..1 # Looks like you failed 1 test of 1. τϨʔε͕յΕΔ ςετग़ྗ
  51. ͳͥʁ

  52. 5FTU"1*QN &/%ͷͱ͖͸ৗʹDBMMFS  ʹͳΔ

  53. 5FTU"1*QN

  54. w ͦ΋ͦ΋&/%ͷڍಈ͸೉͍͠ w &/%Λར༻ͯ͠ςετΛݺΜͰ͍Δ έʔε͸ผͷํ๏Λར༻͢Δ

  55. package t::test; use Hook::AfterRuntime (); sub import { my $pkg

    = caller; eval qq{ package $pkg; use parent qw/Test::Class/; use Test::More; }; Hook::AfterRuntime::after_runtime { $pkg->runtests; }; }
  56. package Foo; use strict; use warnings; use t::test; sub foo

    : Tests { } package Foo; use t::test; use warnings; use strict; my $__ENDRUNAAAAAAAA = 'Hook::AfterRuntime'->new(0); sub foo { &pass(); } package Foo; use attributes ('Foo', sub { package Foo; use warnings; use strict; &pass(); } , 'Tests'); %FQBSTF σετϥΫλ͕ݺ͹ΕΔ ϑΝΠϧ ͷऴΘΓ ίʔυΛJNQPSUઌʹ ૠೖ͍ͯ͠Δ
  57. ϞϯΩʔύον͍ͯ͠Δ ςετϞδϡʔϧ΋յΕΔ

  58. w 5FTU1SFUUZ w 5FTU8BSOJOHT

  59. 5FTUʹΑΔϝϦοτ΋͋Δ

  60. 5FTUͰςετ Λॻ͘

  61. 5FTU4VJUF

  62. 5FTUΛϕʔεʹ
 ศརͳςετؔ਺Λఏڙ

  63. VTF5FTU7

  64. DPNQBSF σʔλߏ଄ͷൺֱ 5FTU%FFQ

  65. JT  JT@EFFQMZ  DNQ@EFFQMZ JT  MJLF

  66. my $ref = {a => 1, b => 2, c

    => [1, 2, 3]} # σʔλߏ଄͕ਖ਼͍͔͠νΣοΫ is $ref, {a => 1, b => 2, c = [1, 2, 3]}; # ࢦఆͨ͠΋ͷҎ֎͸νΣοΫ͠ͳ͍ like $ref, {b => 2};
  67. ςετ͕GBJMͨ͠ͱ͖ͷग़ྗ

  68. use Test2::V0; my $ref = {a => ['A'], b =>

    'baz'}; like $ref, hash { field a => array { item 'a' }; field b => match qr/bar/; # ଘࡏ͢Δ͔ field c => E(); end(); };
  69. not ok 1 # Failed test at test.t line 9.

    # +--------+-----------------------+---------+--------------+------+ # | PATH | GOT | OP | CHECK | LNs | # +--------+-----------------------+---------+--------------+------+ # | | HASH(0x7fbddc028400) | | <HASH> | 3, 9 | # | {a} | ARRAY(0x7fbddc028418) | | <ARRAY> | 4 | # | {a}[0] | A | eq | a | 4 | # | {b} | baz | =~ | (?^:bar) | 5 | # | {c} | <DOES NOT EXIST> | !exists | <DOES EXIST> | 7 | # +--------+-----------------------+---------+--------------+------+ ςετग़ྗ
  70. NPDL ϞοΫ 5FTU.PDL(VBSE

  71. my $mock = mock 'Foo' => ( add => [add_method

    => sub { ... }], override => [replace_method => sub { ... }], ); Foo->add_method; Foo->replaced_method;
  72. w BEE PWFSSJEF w CFGPSF BGUFS BSPVOE w $MBTT.FUIPE.PEJpFSTΈ͍ͨͳͷ w

    5FTU.PDL(VBSEͰ͸೉͔ͬͨ͠
  73. FYDFQUJPO ྫ֎ͷνΣοΫ 5FTU'BUBM
 5FTU&YDFQUJPO

  74. like(dies { die 'xxx' }, qr/xxx/); ok(lives { ... });

  75. XBSOJOHT ܯࠂͷνΣοΫ 5FTU8BSO 5FTU8BSOJOHT

  76. like warning { warn 'xxx' }, qr/xxx/; ok no_warnings {

    ... };
  77. ཚ਺ͷTFFEʹ஫ҙ w σϑΥϧτͩͱຊ೔ͷ೔෇
 4FFEFETSBOEXJUITFFEGSPNMPDBMEBUF w ؀ڥม਺5@3"/%@4&&%ͰࢦఆՄೳ JTB@PLͷڍಈʹ΋஫ҙ

  78. my $ref = {}; ref_ok($ref, 'HASH', 'ϋογϡϦϑΝϨϯε͔Ͳ͏͔'); isa_ok([], 'ARRAY'); #

    Failed test 'ARRAY->isa('ARRAY')' # at test.t line 3. # ARRAY is neither a blessed reference or a package name. 5FTU4VJUFͷJTB@PLͷڍಈ͸5FTU.PSFͱҟͳΔ
  79. ςετ ศར৘ใ

  80. ςετΛͭͷؔ਺ʹ ·ͱΊΔ

  81. use Test::More; sub my_ok { ok($_[0]); } my_ok(0); my_ok(0); not

    ok 1 # Failed test at test.pl line 4. not ok 2 # Failed test at test.pl line 4. Ͳͷݺͼग़͠ݩͰGBJM͔ͨ͠Θ͔Βͳ͘ͳΔ
  82. ղܾํ๏ ্ͭͷDBMMTUBDLΛݟΔΑ͏ ʹ఻͑Δ

  83. use Test::More; sub my_ok { local $Test::Builder::Level = $Test::Builder::Level +

    1; ok($_[0]); } 5FTU#VJMEFS MPDBM5FTU#VJMEFS-FWFM  ͱॻ͍ͯ͸͍͚ͳ͍
  84. use Test::More; use Test2::API qw/context/; sub my_ok { my $ctx

    = context(); ok($_[0]); $ctx->release; } 5FTU
  85. not ok 1 # Failed test at test.pl line 10.

    not ok 2 # Failed test at test.pl line 11.
  86. 5FTU1MVHJO4PVSDF%JBH

  87. ςετͷग़ྗ݁Ռʹ GBJMͨ͠ߦͷιʔείʔυΛ දࣔ

  88. use Test2::V0; use Test2::Plugin::SourceDiag; my $something = 'test'; my $pat

    = qr/test2/; like $something, $pat; done_testing;
  89. not ok 1 - is $something, $pat; # Failed test

    'is $something, $pat;' # at test.t line 6. # +------+----+------------+ # | GOT | OP | CHECK | # +------+----+------------+ # | test | =~ | (?^:test2) | # +------+----+------------+ ςετग़ྗ
  90. 5FTU%FFQͷΑ͏ʹॻ͖͍ͨ

  91. 5FTU%FFQ-JLF HJUIVCDPNBLJZN5FTU%FFQ-JLF

  92. use Test::Deep; cmp_deeply $foo, isa('Foo') & methods(foo => 'FOO'); 5FTU%FFQ

    5FTU4VJUF use Test2::V0; is $foo, object { prop blessed => 'Foo'; call foo => 'FOO'; };
  93. use Test2::V0; use Test2::DeepLike; is $foo, isa('Foo') & methods(foo =>

    'FOO'); 5FTU%FFQ-JLF
  94. not ok 1 # Failed test at t/methods.t line 16.

    # Compared $data->foo # got : 'BAR' # expect : 'FOO' 5FTU%FFQ 5FTU%FFQ-JLF not ok 1 # Failed test at t/methods.t line 16. # +-------+-----+----+-------+ # | PATH | GOT | OP | CHECK | # +-------+-----+----+-------+ # | foo() | BAR | eq | FOO | # +-------+-----+----+-------+
  95. use Test2::V0; use Test2::DeepLike; my $foo = bless {}, 'Foo';

    my $bar = bless {}, 'Bar'; is [$foo, $bar], bag(isa('Foo'), isa('Baz'));
  96. not ok 1 # Failed test at test.t line 7.

    # Comparing $data as a Bag # Missing: 1 reference # Extra: 1 reference 5FTU%FFQ 5FTU%FFQ-JLF not ok 1 # Failed test at test.t line 7. # +------+--------------------------+---------+------------------+-----+ # | PATH | GOT | OP | CHECK | LNs | # +------+--------------------------+---------+------------------+-----+ # | [*] | <DOES NOT EXIST> | ISA | Baz | 7 | # | [1] | Bar=HASH(0x7f91c0803268) | !exists | <DOES NOT EXIST> | | # +------+--------------------------+---------+------------------+-----+
  97. ·ͱΊ

  98. w ςετϞδϡʔϧͷ঺հ w 5FTUҠߦͷ஫ҙ఺ w VTF5FTU1MVHJO65' w 5FTUͷςετͷॻ͖ํ w 5FTUͰςετΛศརʹ͢Δ