testing scripts

15
Testing Scripts Randal L. Schwartz, [email protected] Version LT-1.05 on 13 Jun 2012 This document is copyright 2012 by Randal L. Schwartz, Stonehenge Consulting Services, Inc. This work is licensed under Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License http://creativecommons.org/licenses/by-nc-sa/3.0/ 1 Monday, June 25, 12

Upload: randal-schwartz

Post on 07-Feb-2015

1.237 views

Category:

Technology


3 download

DESCRIPTION

My YAPC::NA 2012 Lightning Talk (5 minutes) on testing scripts using Test::Trap and other tools.

TRANSCRIPT

Page 1: Testing scripts

Testing Scripts Randal L. Schwartz, [email protected]

Version LT-1.05 on 13 Jun 2012

This document is copyright 2012 by Randal L. Schwartz, Stonehenge Consulting Services, Inc.This work is licensed under Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License

http://creativecommons.org/licenses/by-nc-sa/3.0/

1Monday, June 25, 12

Page 2: Testing scripts

• Problem:• Ya gotta test!

• Solution:• use Test::More and friends

• But:• What about scripts!

2Monday, June 25, 12

Page 3: Testing scripts

• Problem:• scripts are separate process• hard to mock things

• Solution:• Don’t use a separate process• Require your script in your .t

• But:• How will I invoke it then?

3Monday, June 25, 12

Page 4: Testing scripts

• Problem:• Loose code is effectively “main”

• Solution:• Bundle loose code into a run subroutine:

sub run { ... }• Also ensure true value at end of script

• But:• What will invoke “run” then?

4Monday, June 25, 12

Page 5: Testing scripts

• Problem:• Invoke “run” when run normally• Don’t invoke “run” via require

• Solution:• Use “caller”:

run(@ARGV) unless caller;• But:• What about namespace of .t file

5Monday, June 25, 12

Page 6: Testing scripts

• Problem:• Collision between script and .t names

• Solution:• Bring it into its own package:

BEGIN { package Program; require "your-script"; die $@ if $@;}

• But:• How to “invoke the program” from tests?

6Monday, June 25, 12

Page 7: Testing scripts

• Problem:• Simulate execution

• Solution:• Invoke run() with desired @ARGV:

subtest try_it => sub { Program::run(qw(--foo --bar abc));};

• But:• What about exceptions, exit, stdout?

7Monday, June 25, 12

Page 8: Testing scripts

• Problem:• Trapping everything (not just die)• eval doesn’t cut it!

• Solution:• Test::Trap!

use Test::Trap;trap { Program::run(qw(--foo --bar abc));};

• But:• How will I know how the code finished?

8Monday, June 25, 12

Page 9: Testing scripts

• Problem:• Was it normal exit, “exit”, or die?

• Solution:• examine $trap object after trap { .. }

ok $trap->exit, 0, "exited 0";like $trap->die, qr{missing args};

• But:• What about stdout, stderr, warnings?

9Monday, June 25, 12

Page 10: Testing scripts

• Problem:• What about those outputs?

• Solution:• Test::Trap captures those too!

like $trap->stdout, qr{usage};is $trap->stderr, q{}, "quiet errors";is @{$trap->warn}, 1, "exactly 1 warn";

• But:• What about stubbing or mocking?

10Monday, June 25, 12

Page 11: Testing scripts

• Problem:• Want to override some behavior

• Solution:• Monkey patching!

subtest stub_it => sub { local *Program::some_sub = sub { ... }; trap { Program::run() };};

• But:• What about stdin?

11Monday, June 25, 12

Page 12: Testing scripts

• Problem:• Provide stdin for script

• Solution:• Small matter of programming:

local *STDIN;open STDIN, "<", (my $S = \join(q{}));$$S .= "one\ntwo\nthree\n";trap { ... };$$S .= "four\nfive\n"; trap { ... };

• But:• What about chdir?

12Monday, June 25, 12

Page 13: Testing scripts

• Problem:• chdir has global effect

• Solution:• Test::Trap is pluggable!

use Test::Trap::mine qw(:cwd);trap { chdir "/tmp"; Program::run() };

• See my blog, or might be core now• But:• Does this really work for all scripts

13Monday, June 25, 12

Page 14: Testing scripts

• Problem:• Script might need complex interaction• Maybe can’t edit code into run()• Code might fork

• Solution:• Yeah, traditional subprocesses• Perhaps combined with Expect

• But:• Test::Trap is amazingly useful!

14Monday, June 25, 12

Page 15: Testing scripts

Follow me

• Twitter: @merlyn• G+: Randal L. Schwartz• Personal blog: merlyn.posterous.com• http://blogs.perl.org/users/randal_l_schwartz/• merlyn, realmerlyn, or RandalSchwartz

15Monday, June 25, 12