Test::More with PHP

petdance on 2003-08-20T16:23:50

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.


Testing Protocol

Ovid on 2003-08-20T16:33:44

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).

Test::More w/ PHP

inkdroid on 2003-08-20T16:47:49

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 .pm files during make install.

A good code can Test::More in any language

jdavidb on 2003-08-20T17:26:05

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.

vb harness started

plural on 2003-08-21T04:37:13

well, I started on the VB.NET interface based on the PHP file posted (many thanks, Andy!). is and like are not valid function names in VB.NET, but i may preface the testing functions with vb_ anyway, so that should be ok.

when i get something other than an empty shell that produces no build errors, I will post it up for comments.

Me too!

Adrian on 2003-08-21T11:03:49

The Test::Harness protocol is one of the things I like most about Perl's testing framework.

In a recent job I had a bunch of code with tests written in C. Quick hack to output the approriate "ok" and "not ok" lines and I have instant integration with the rest of the test suite. Very nice.

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.