IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Ah, that makes sense
There are several ways to do this.

My inclination is to work from the right data structure. Something like this:
\nmy @actions = (\n  "Here is a description of foo.",\n  &foo,\n  "Here is a description of bar.",\n  &bar,\n);\n\nprint "This is a test program!  Here is the plan:\\n\\n";\nmy $count = 0;\nfor my $action (@actions) {\n  next if ref($action);\n  $count++;\n  print "Step $count:\\n$action\\n\\n";\n}\n\nprint "Let's go!";\n\n$count = 0;\nfor my $action (@actions) {\n  if (ref($action)) {\n    $action->(); # do it\n  }\n  else {\n    $count++;\n    print "\\n\\nStep $count:\\n$action";\n  }\n}\n\nsub foo {\n  # ...\n}\n\nsub bar {\n  # ...\n}\n

This works and avoids doing any cleverly deep magic. Unfortunately you do have to structure your program just so for it to work - you can't easily retrofit this onto an existing script.

You can also generalize this. For instance you could store an array of anonymous hash references, which have a description and a function attached. And then you could dynamically put together a test plan, describe it, then do it.

But if you want to go with your original strategy, then you can use Filter::Simple. The idea being that you can just use source filtering to design a construct that will build a data structure up front, print it, then emit messages later on. That would be something like this:

\n#### Filter/ShowSteps.pm #######\n\npackage Filter::ShowSteps;\n\nuse Filter::Simple;\n@ISA = 'Filter::Simple';\n\nuse strict;\n\nmy @steps;\n\nFILTER {\n  # Original code is passed in in $_.\n  # Modified code is whatever ends up in $_.\n\n  my $is_code = 1;\n  my @code;\n  for my $piece (split /\\n-----+\\n/, $_) {\n    if ($is_code) {\n      push @code, $piece;\n    }\n    else {\n      push @steps, $piece;\n      push @code, join "\\n",\n        "Filter::ShowSteps::show(<<'END_OF_COMMENT');",\n        $piece,\n        "END_OF_COMMENT";\n    }\n    $is_code = !$is_code;\n  }\n  $_ = join "\\n", @code;\n};\n\nsub show {\n  print "\\n", @_;\n}\n\nsub show_all {\n  print "$_\\n" for @steps;\n}\n\n1;\n\n#### some program #######\n\n#! /usr/bin/perl -w\nuse strict;\n\nuse Filter::ShowSteps;\n\nprint "This is a test program!  Here is the plan:\\n\\n";\n\nFilter::ShowSteps::show_all();\n\nprint "\\nNow here we go!\\n\\n";\n\n---------------------------\nThis is the first step.\n---------------------------\nprint "Do something.\\n";\n\n---------------------------\nThis is the second step.\n---------------------------\nprint "Do something else.\\n";\n

(I didn't mean to write your program for you, but I guess I did...)

Cheers,
Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New Well, not exactly what I had in mind...
\ntestDescription(<<end);\nThis test checks that widgets can mate with thingamaboobs\nend\n\n\ntestStep("create a gray widget");\n...\ntestStep("create a red thigamaboob");\n...\ntestStep("mate the widget and the thigamaboob");\n...\ntestStep("verify that the result is gray with red stripes");\n\n



In my previous implementation, I used the following

\ntestDescription(<<end);\nThis test checks that widgets can mate with thingamaboobs\n\n- create a gray widget\n- create a red thigamaboob\n- mate the widget and the thigamaboob\n- verify that the result is gray with red stripes\n\nend\n\n\ntestStep();\n...\ntestStep();\n...\ntestStep();\n...\ntestStep();\n


The test support code would parse a bunc hof " - xxx" at the end of test descrioption, and use them to notify the user of test step being taken.

That, of course, was quite fragile. More importantly, the self-documenting value of testStep was completely lost.

So the question is - how do I extract the test steps from the code? I was thinking about using compilation pass. Now that I look at it again - it seems that I could open the script file from inside testDescription, and grep for testStep() - God forgive me.

------

179. I will not outsource core functions.
--
[link|http://omega.med.yale.edu/~pcy5/misc/overlord2.htm|.]

New You can get where you want to go
But I wouldn't suggest going there.

If you're going to write normal Perl, write normal Perl. If you're not going to write normal Perl, make it look like it isn't normal Perl.

With source filters you can do what you're asking for. However your maintainance programmer will (or at least should) hunt you down with a blunt weapon. But consider something like this which has (modulo syntax) the exact same structure as your program:
\nEND {\n  # This is executed last, even though it appears first.\n  print "This test checks that widgets can mate with thingamaboobs\\n";\n  show_plan();\n  do_plan();\n}\n\nplan(\n  "create a gray widget",\n  sub {\n    ...\n  }\n);\n\nplan(\n  "create a red thigamaboob",\n  sub {\n    ...\n  }\n);\n\n...\n\n

This is easy to implement, does what you're asking for, and it is fairly obvious to the maintainance programmer how the magic works.

Incidentally if you're doing automatic unit tests, is there a good reason not to be using Test::More? Perl has good facilities for such test suites, you just have to use them. (Ignore this comment if the point of your test suite is to have someone look at the screen and manually review that what shows up matches what was supposed to show up.)

Cheers,
Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New OK, I'll consider your idea
The thing is, this stuff will be used by people who don't know Perl and (probably for that reason) don't love Perl. It takes all my efforts to get them to use my framework at all. If I have to explain constructs like

plan("xxx" sub{...})

I'll never get anything done at all;

The framework I am using is not for unit test - it's for system tests. It has two main classes - Executable and FileTail. One starts a process and lets me send to its stdin, and the other lets me tail a file. This is used in the context of our runtime environment, starting clients and servers, feeding data and checking what comes out. I am not sure how Test::More would help me there.

------

179. I will not outsource core functions.
--
[link|http://omega.med.yale.edu/~pcy5/misc/overlord2.htm|.]

     Perl Q: can I define my own use() (and a bit more)? - (Arkadiy) - (6)
         All things are possible - (ben_tilly) - (5)
             Description of test steps - (Arkadiy) - (4)
                 Ah, that makes sense - (ben_tilly) - (3)
                     Well, not exactly what I had in mind... - (Arkadiy) - (2)
                         You can get where you want to go - (ben_tilly) - (1)
                             OK, I'll consider your idea - (Arkadiy)

Any more detail than what's there and you'd have to have the magic software they use in movies to pull a license plate out of five pixels.
49 ms