At Monday's Chicago Perl Mongers meeting, I talked to Jason Gessner about faking the Perl Test::Harness protocol in other languages. He asked for the PHP module that I wrote to do it for PHP. Here it is:
$_test_ntests = 0;
$_nfailures = 0;
$_ended = 0;
$_no_plan = 0;
register_shutdown_function( '_test_for_ending' );
function ok( $condition, $name = '' ) {
global $_test_ntests;
global $_nfailures;
++$_test_ntests;
if ( !$condition ) {
print "not ";
++$_nfailures;
}
print "ok $_test_ntests";
if ( $name != "" ) {
print " - $name";
}
print "\n";
return $condition;
}
function pass( $name = '' ) {
return ok( TRUE, $name );
}
function fail( $name = '' ) {
return ok( FALSE, $name );
}
function skip( $msg, $num ) {
for ( $i=0; $i<$num; $i++ ) {
pass( "# SKIP $msg" );
}
}
function is( $actual, $expected, $name = '' ) {
$ok = ($expected == $actual);
ok( $ok, $name );
if ( !$ok ) {
diag( "Expected \"$expected\"" );
diag( " but got \"$actual\"" );
}
return $ok;
}
function isnt( $actual, $dontwant, $name = '' ) {
$ok = ($actual != $dontwant);
ok( $ok, $name );
if ( !$ok ) {
diag( "Didn't want \"$actual\"" );
}
return $ok;
}
function isa_ok( $object, $class, $name = null ) {
if ( isset( $object ) ) {
$actual = get_class( $object );
if ( !isset( $name ) ) {
$name = "Object is of type $class";
}
return is( get_class( $object ), strtolower( $class ), $name );
} else {
return fail( "object is undefined" );
}
}
function like( $string, $regex, $name='' ) {
return ok( preg_match( $regex, $string ), $name );
}
// We diag() to stderr instead of stdout like Perl does. It shouldn't
// make any difference to the harness.
function diag( $lines ) {
if ( is_string( $lines ) ) {
$lines = split( "\n", $lines );
}
foreach ( $lines as $str ) {
print "# $str\n";
}
}
function plan( $ntests ) {
print "1..$ntests\n";
}
function no_plan() {
global $_no_plan;
$_no_plan = 1;
}
function test_end() {
global $_no_plan;
global $_test_ntests;
if ( $_no_plan ) {
print "1..$_test_ntests\n";
}
global $_ended;
$_ended = 1;
$ver = phpversion();
if ( version_compare( $ver, '4.2.2' ) > 0 ) { # >4.2.2?
global $_nfailures;
exit( $_nfailures > 254 ? 254 : $_nfailures );
} else {
# Don't return anything
}
}
function html_ok( $str, $name = "" ) {
$fname = tempnam( getenv("TMP"), 'lint-' );
$fh = fopen( $fname, "w" );
fwrite( $fh, $str );
fclose( $fh );
$results = Array();
$results = shell_exec( "weblint $fname" );
unlink( $fname );
if ( $results ) {
$ok = fail( $name );
diag( $results );
} else {
$ok = pass( $name );
}
return $ok;
}
function _test_for_ending() {
global $_ended;
if ( !$_ended ) {
fail( "Didn't call test_end()" );
}
}
?>
Note that html_ok() is from Test::HTML::Lint.
You know, this looks like you're well on your way to creating the testing protocol that was discussed. By distributing a set of standard tools in various languages, one can implement the protocol rather than wait for people to adopt the proposal. That could be a sneaky end run around a lot of common objections.
And since I had already started writing testing software for Python that mirrors Test::More, it looks like we could get a jump on that, too. Of course, there are those who suggest the more traditional FooUnit type of frameworks. Since I'm less familiar with those, I don't know if they're a better option or not (though they are more common).
Would it be outlandish to have the Test::More distro actually include foreign language (non-Perl) files which would generate suitable output suitable for Test::Harness?
Having these could leverage Perl as general purpose testing language since it would allow you to have a single test suite that tested code in Perl *and* PHP, Python, Java (etc).
These hypothetical TestMore.php and TestMore.java files could live in a subdir of the distro, and not get installed with the other
I've been using a PL/SQL package I made called T to do this, sort of. Probably not complex enough to interface with Test::Harness, yet.
Even though Perl isn't a part of my job description any more, the things I have learned and continue to learn through the Perl community still help me constantly.
Testing Fromeworks in a lot of languages
Bernhard on 2003-09-01T09:40:53
I thought that cross language testing frameworks are already reality, as seen on http://www.xprogramming.com/software.htm. The other place where Test::Harness is used for testing a bunch of languages is in the Parrot project.Re:Testing Fromeworks in a lot of languages
Adrian on 2003-09-01T21:51:46
Afraid not. The various xUnit frameworks don't support multiple languages - they're just the same framework (class hierarchy wise) implemented in several different languages. For example, you can't analyse Smalltalk test results in JUnit or Java test results in SUnit.
What the xUnit frameworks lack is a language independent way of communicating test results to the test runner. Perl has the Test::Harness protocol. As long as the test script outputs the appropriate "ok" / "not ok" lines it can be fed into Test::Harness. One of the (several) advantages of the Perl testing framework in my opinion.