parameterization of perl *.t Prove existing tests - perl

I have a bunch of perl tests:
Functional Tests
Mechanize Tests
Actual Unit Tests, asserting on functions and return values, etc
Tests that involve external Services, like WebServices
DB centric tests
REST tests
I run all of them via prove and theoretically re-arrange them into various directories and run something like find t/ -name '*.t' ! -name '*timeout*' | xargs prove -l, but gets very difficult (and not good engineering) to name tests a particular way, so we can parse them via find.
Is there a way we can pass a wildcard list of tests to prove when we run it via command line?
If not, is there a more sane approach than what we're currently using?

The usual way to to this is via environment variables. The test file checks whether it's supposed to run, and if it's not does a quick skip_all.
For example:
use strict;
use warnings;
use Test::More;
BEGIN {
plan skip_all => "not running extended tests" unless $ENV{EXTENDED_TESTING};
};
# your slow tests here
done_testing();
Now usually that test will be skipped. But if you set the EXTENDED_TESTING environment variable to "1", it will run.
Standard environment variables include EXTENDED_TESTING, RELEASE_TESTING, and NONINTERACTIVE_TESTING. NO_NETWORK_TESTING is also catching on.
There are various modules to automate this such as Test::Is which allows the simpler syntax:
use strict;
use warnings;
use Test::More;
use Test::Is "extended";
# your slow tests here
done_testing();
If you have some other application-specific categories, you'll have to invent some environment variables yourself. If you think they seem generically useful, blog about them, and maybe they'll catch on and become standard environment variables too.

i think i found the answer as Test::Less
Test::Less - Test Categorization and Subset Execution
test-less normally keeps the index file of mappings between tags and test files, in a file called t/Test-Less/index.txt. You can override this with the --file option or the TEST_LESS_INDEX environment variable.
Tags are strings matching /^[\w\-]+$/.
The -list and -prove commands take what is called a tag specification.
A specication is a a list of tags and possibly file names.
test-less -prove foo bar baz
Runs all the foo tests, bar tests and baz tests.
test-less -prove foo,bar,baz
Even after i was able to fix the compile bug in Test::Less, i was still unable to run any tests using Test::Less which has been broken since 2009. So looking at Test::Class might be the answer:
http://search.cpan.org/~ether/Test-Class-0.46/lib/Test/Class.pm
Sometimes you just want to run a single test. Commenting out other tests or writing code to skip them can be a hassle, so you can specify the TEST_METHOD environment variable. The value is expected to be a valid regular expression and, if present, only runs test methods whose names match the regular expression. Startup, setup, teardown and shutdown tests will still be run.
One easy way of doing this is by specifying the environment variable before the runtests method is called.
Running a test named customer_profile:
#! /usr/bin/perl
use Example::Test;
$ENV{TEST_METHOD} = 'customer_profile';
Test::Class->runtests;
Running all tests with customer in their name:
#! /usr/bin/perl
use Example::Test;
$ENV{TEST_METHOD} = '.*customer.*';
Test::Class->runtests;

Related

Autoconf : How to get program output in a string and check if another string is present in that

I am developing a Qt application in Python. It uses a resource file, which needs to be compiled. I am using autotools to manage compilation and installation of my projects.
Now, in order for the resource file to be usable by the application, it needs to be compiled with a certain version of the compilation program (pyrcc). I can get the version by putting the output of pyrcc -version in a variable in configure.ac. But then, I don't know how to check whether the string pyrcc5 is present in the output. If it is not present, I want to tell the user that his PyRCC programm has the wrong version, and abort configure.
Additionally, I would like to avoid the need of an extra variable for the program output, but instead do it like this (Pseudo code):
if "pyrcc5" not in output of "pyrcc -version":
say "pyrcc has wrong version"
exit 1
How can I do this ?
When writing a configure.ac for Autoconf, always remember that you are basically writing a shell script. Autoconf provides a host of macros that afford you a lot of leverage, but you can usually at least get an idea about basic "How can I do X in Autoconf?" questions by asking instead "How would I do X in a portable shell script?"
In particular, for ...
I would like to avoid the need of an extra variable for the program
output, but instead do it like this (Pseudo code):
if "pyrcc5" not in output of "pyrcc -version":
say "pyrcc has wrong version"
exit 1
... the usual tool for a portable shell script to use for such a task is grep, and, happily, the easiest way to apply it to the task does not require an intermediate variable. For example, this implements exactly your pseudocode (without emitting any extraneous messaging to the console):
if ! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null; then
echo "pyrcc has wrong version"
exit 1
fi
That pipes the output of pyrcc -version into grep, and relies on the fact that grep exits with a success status if and only if it finds any matches.
You could, in fact, put exactly that in your configure.ac, but it would be more idiomatic to
Use the usual Autoconf mechanisms to locate pyrcc and grep, and to use the versions discovered that way;
Use the Autoconf AS_IF macro to write the if construct, instead of writing it literally;
Use standard Autoconf mechanisms for emitting a "checking..." message and reporting on its result; and
Use the standard Autoconf mechanism for outputting a failure message and terminating.
Of course, all of that makes the above considerably more complex, but also more flexible and portable. It might look like this:
AC_ARG_VAR([PYRCC], [The name or full path of pyrcc. Version 5 is required.])
# ...
AC_PROG_GREP
AC_CHECK_PROGS([PYRCC], [pyrcc5 pyrcc], [])
AS_IF([test "x${PYRCC}" = x],
[AC_MSG_ERROR([Required program pyrcc was not found])])
# ...
AC_MSG_CHECKING([whether ${PYRCC} has an appropriate version])
AS_IF([! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null], [
AC_MSG_RESULT([no])
AC_MSG_ERROR([pyrcc version 5 is required, but ${PYRCC} is a different version])
], [
AC_MSG_RESULT([yes])
])
In addition to portability and conventional Autoconf progress messaging, that also gets the builder a way to specify a particular pyrcc executable to configure (by setting variable PYRCC in its environment), documents that in configure's help text, and exports PYRCC as a make variable.
Oh, and I snuck in a check for pyrcc under the name pyrcc5, too, though I don't know whether that's useful in practice.
The final result no longer looks much like the shell script fragment I offered first, I grant. But again, the pure shell script fragment could be used as is, and also, the fully Autoconfiscated version is derived directly from the pure script.

How to test a single failing test when building perl

This issue usually is encountered when trying to run make test and sees one test fails. The README describes one can run each test individually, didn't clearly specifies how to do so.
make test uses the script called TEST in the test directory (t). To replicate make test of a single file, one would use this script as follows:
[.../perl/t]$ ./perl -I../lib TEST op/array.t
t/op/array ... ok
All tests successful.
Elapsed: 0 sec
u=0.01 s=0.00 cu=0.03 cs=0.02 scripts=1 tests=194
If you want to see the raw output of the test script, you can run perl as follows:
[.../perl/t]$ ./perl -I../lib op/array.t
1..194
ok 1
ok 2
ok 3
...
ok 192 - holes passed to sub do not lose their position (multideref, mg)
ok 193 - holes passed to sub do not lose their position (aelem)
ok 194 - holes passed to sub do not lose their position (aelem, mg)
The above information and more is found in perlhack.
This document explains how Perl development works. It includes details about the Perl 5 Porters email list, the Perl repository, the Perlbug bug tracker, patch guidelines, and commentary on Perl development philosophy.
Note that you need to run make test_prep before the above commands work. (If you've run make test, you've effectively run make test_prep already.)
Run ./perl harness ../foo/boo.t in the t directory, with foo/boo the name of the failing test.
To run a single test script, use perl, or better, prove. Assuming you are in the module's base directory:
prove -lv t/some-test-script.t
This will run the test script against the libraries in ./lib, with fallback to the libraries available to your install of Perl.
If you want to use the build libraries built by make, then this:
prove -bv t/some-test-script.t
Now the test script will be run against the libraries in ./blib, falling back to libraries installed for your Perl.
The test scripts are typically just Perl scripts that live in a t/ or xt/ or some similar path within the distribution's directory structure. So you can also run them just with Perl:
perl -Iblib t/some-test-script.t
But prove produces nicer test summary information and color coding.
That is about as granular as you can get unless tests are written to allow for targeting specific segments within a test script. If you need to target a specific test within a test script you'll usually have to dig into the test code itself.

Perl debugger on test modules

I'm running into problems testing a new addition to a module. (Specifically - the ~ operator seems to be not working in Math::Complex for this new feature only.) It's too bizarre to be what it appears but the ideal scheme would be to add the -d option on the top line of the .t program.
Well, I was quickly disabused of that idea! It does not invoke the debugger.
If I wanted to use the debugger, I'd need to create an edit of the .t program that:
Uses (the use command) the module directly. not in the form of
BEGIN { use_ok('My::Module') };
Does not "use Test::More;"
A few other edits that cause gluteal pains
The problem with doing that is that any changes I make in the edited test program I still need to transfer back to the true test program use in "make test". Error prone as best.
I am already using "make test TEST_VERBOSE=1" so that my stdio output shows up. But there's GOT to be a simpler way to invoke the debugger on the .t
Thanks for ideas here.
-- JS
use_ok tests are great, but you should have them in test files of their own, not test files that also test other things.
I'm not sure why you would need to avoid Test::More or use_ok to run the debugger, though. What does happen when you try your test directly:
perl -d -Mblib t/yourtestfile.t?
If all else fails, you can try using Enbugger in your test script.

How can I control the order of execution for TestSuites?

I have a number of test suites that make use of the Test::Unit::TestCase package and since it is a parallel environment I need to modify them to ensure that one TestSuite does not start until another has completed. Based upon the documentation it appears that there is a way to control the order of the suite execution:
If you need to specify the test order, you can do one of the
following:
Provide a suite() method which returns a Test::Unit::TestSuite.
However, there don't appear to be any examples of how to do this. Is this actually possible and if so how should it be done?
Tests are insightful.
$ cpanm --look Test::Unit::TestCase
$ ack -l 'sub suite' t
t/tlib/SuiteTest.pm
t/tlib/AssertTest.pm
t/tlib/AllTests.pm

How can I run a test perl script designed for prove form inside TextMate?

I'm using TextMate 1.5.10 (Mac OSX 10.7.2) to write a perl modulino application. To verify the functionality, I'm using test scripts designed to be run with the prove command line tool.
An example of the directory structure I'm using looks like this:
text_mate_test/MyModule.pm
text_mate_test/t/001_load_test.t
The 001_load_test.t file looks like this:
#!/usr/bin/perl
use Modern::Perl;
use Test::More;
use MyModule;
my $testObj = new_ok("MyModule", undef, "Initial load test.");
done_testing();
When I run prove or prove -v in the "text_mate_test" directory, everything passes as expected.
I'd like to be able to setup a hotkey in TextMate that allows me to run the test file without having to jump over to the terminal. Currently, if I run "001_load_test.t" directly from inside TextMate with Cmd+R, it chokes saying "Can't locate MyModule.pm in #INC". That's expected since the test script isn't designed to run directly. (I'm still pretty new to writing test files, but I believe that's the proper way to set them up.)
Running off the assumption that I don't want to change the test file itself, is there a way to setup a hotkey so I can run the file accurately from inside TextMate?
I've figured out an even better way to do this.
In the TextMate Bundle Editor (Menubar -> Bundles -> Bundle Editor -> Show Bundle Editor), I've updated the default "Perl -> Run Script" bundle to this:
#!/usr/bin/env ruby
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/executor"
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/save_current_document"
TextMate.save_current_document
TextMate::Executor.make_project_master_current_document
### If it's a ".t" test script in a "t" directory, run prove
if ( ENV["TM_FILEPATH"] =~ /^.*\/(t\/[^\/]+)$/ )
### Grab the relative file path for more legible output
relative_file_path = $1
### Jump up one directory so prove will work
Dir.chdir("../");
### Call prove with args to run only the file you are working on.
TextMate::Executor.run("prove", :script_args => ["-v", relative_file_path]);
### Otherwise, run with perl
else
TextMate::Executor.run(ENV["TM_PERL"] || "perl", "-I#{ENV["TM_BUNDLE_SUPPORT"]}",
"-Mexception_handler", ENV["TM_FILEPATH"],
:version_args => ["-e", 'printf "Perl v%vd", $^V;'])
end
Here's a screenshot of how it looks in the Bundle Editor.
The benefit of this is that you can use the same hot key (Cmd+r by default) to run your normal scripts with perl and your test scripts with prove.
This is what I was looking for.
UPDATED: When I first developed this, I only had one test script in the "t" directory. I didn't notice until I added other test scripts that the code in the original version of this answer would run prove across all the scripts. Not just the one being worked on. To get back to the expected behavior, I've update the bundle code so that prove will only run on the active script.
I've come up with a solution. Create a new Perl bundle called "Run Script with prove" and associate it with Shift-Cmd-R. The code for the bundle is:
#!/usr/bin/env ruby
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/executor"
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/save_current_document"
TextMate.save_current_document
TextMate::Executor.make_project_master_current_document
### If it's a ".t" test script in a "t" directory, run prove
if ( ENV["TM_FILEPATH"] =~ /^.*\/(t\/[^\/]+)$/ )
### Use the relative file path for more legible output
relative_file_path = $1
### Jump up one directory so prove will work
Dir.chdir("../");
### Call prove with args to run only the file you are working on.
TextMate::Executor.run("prove", :script_args => ["-v", relative_file_path]);
else
error_string = "This script's filepath doesn't end with /t/.*\.t\n"
error_string += "That is required for the 'Perl -> Run Script with prove' bundle to work.\n"
TextMate::Executor.run("echo", :script_args => [error_string]);
end
Note: This is the results of a bunch of trial and error hacking. I don't know if it's the "right" to do it, but this works for me. Everything but the last two lines is a copy from the original "Run Script" bundle that comes with TextMate. Based on that, it seems like this should be pretty safe.
UPDATE: When I first built this I only had one test file in the "t" directory. When I added more, I discovered that the original version of the bundle was running all the test files. This code represents an update to the expected behavior of only running the test script you working on. Because of the way I ended up doing that, it also became necessary to add in a fallback. If you try to run a script that doesn't match the standard test file path format, it gives an error message.
It will enable the program to find your module if you add
use lib '..';
to the top of your code (before the use MyModule). This will add the text_mate_test directory to #INC and enable Perl to find the module, though you may come across other problems with running the program directly.