About the Author

Chris Shiflett

Hi, I’m Chris: entrepreneur, community leader, husband, and father. I live and work in Boulder, CO.

Test::Simple for PHP

Via PHPDeveloper.org, I just read a post on PhpGirl that discusses a familiar topic, testing:

I'll write a Test::Simple for PHP. Yes, I know there exists one already that uses the power of Perl to test PHP files, but I didn't have time to figure out how to set that up and probably won't be able to use Perl anyways on the production system.

A few years ago, Geoff Young and I gave a talk called Testing PHP with Perl. We thought we were being funny (in our defense, those who listened to the talk seemed to agree), but I think all we did is make our project seem inaccessible to PHP developers. Perl is scary. :-)

Part of our project is a pure PHP implementation of Test::More. If you want to really keep things dirt simple (which seems to be Nola's goal), you can use it by itself with no framework, but more on that in a minute.

In a follow-up post, Nola describes how she uses her simple testing library. The first argument to ok() is a boolean that indicates whether the test passes. She demonstrates some tests using conditionals that compare two values expected to be equal:

$t->ok($user->getRealName() == 'John Doe Test', 'get RealName'); 
$t->ok($user->getUserName() == 'jdoe', 'get UserName'); 
$t->ok($user->getEmail() == 'john@doe.com', 'get Email'); 
$t->ok($user->getPermission() == 1, 'get Permission'); 

She also demonstrates some tests using conditionals that compare two values expected to not be equal:

$t->ok($user->getRealName() != 'Susie Doe', 'Not Realname Suzie Doe'); 
$t->ok($user->getUserName() != 'sdoe', 'Not Username sdoe'); 
$t->ok($user->getEmail() != 'suz@doe.com', 'Not email suz@doe.com'); 
$t->ok($user->getPermission() != 0, 'Not Permission 0'); 

You can do the same sort of thing with Testmore:

include './testmore.php'; 
include './userclass.php'; 
ok($user->getRealName() == 'John Doe Test', 'get RealName'); 
ok($user->getUserName() == 'jdoe', 'get UserName'); 
ok($user->getEmail() == 'john@doe.com', 'get Email'); 
ok($user->getPermission() == 1, 'get Permission'); 
ok($user->getRealName() != 'Susie Doe', 'Not Realname Suzie Doe'); 
ok($user->getUserName() != 'sdoe', 'Not Username sdoe'); 
ok($user->getEmail() != 'suz@doe.com', 'Not email suz@doe.com'); 
ok($user->getPermission() != 0, 'Not Permission 0'); 

I created a simple userclass.php file to implement the methods she uses:

class user 
    public function getRealName() { return 'John Doe Test'; } 
    public function getUserName() { return 'jdoe'; } 
    public function getEmail() { return 'john@doe.com'; } 
    public function getPermission() { return 1; } 
$user = new user; 

If you just run this PHP script, you'll see the raw TAP output:

ok 1 - get RealName
ok 2 - get UserName
ok 3 - get Email
ok 4 - get Permission
ok 5 - Not Realname Suzie Doe
ok 6 - Not Username sdoe
ok 7 - Not email suz@doe.com
ok 8 - Not Permission 0

If a test fails, the last line lets you know about it (in addition to one of the previous lines being not ok instead of ok):

# Looks like you failed 1 tests of 8.

So, even without a testing framework, you can use Testmore as a simple testing tool. If you want to try it yourself, you can download Apache-Test (it's bundled with the distribution) or grab it from GitHub.

Using Test::Harness to Test PHP Applications, a talk being given at PHP Québec, is supposed to cover this same topic.

About this post

Test::Simple for PHP was posted on Thu, 26 Jan 2006. If you liked it, follow me on Twitter or share:


1.Nola said:

I looked all over for where I could download test-more.php after reading your presentation. Finally (I almost emailed you too!) yesterday when I was trying to get TestConfigPHP working, I found it. I also got Andy Lester's version last night.

I still think I'd rather have it in a class. Having global variables gives me jitters and I like having my "namespace" in my class :) though it would be unlikelly that I would ever have another function called "ok" (etc) in my code.

Interesting using the "register_shutdown_function" never used that before. Thats better than my $t->report(); which today when I was working with it forgot to add it to one of my test files and I was wondering why it didn't spit out the report.

Thanks for the "history" and information.

Thu, 26 Jan 2006 at 18:32:25 GMT Link

2.Chris Shiflett said:

Yeah, Geoff and I have been discussing how to make this stuff more accessible. Not being able to get test-more.php by itself is a problem, which is why I just added a link to it as a temporary solution. We'll probably find a more official way to distribute it soon.

I think your post highlights why this little testing library can be useful. The complex testing libraries like Simple-Test and PHPUnit are great, but neither seem to follow the "PHP way" of keeping things simple. Using test-more.php is easy, and it also provides a nice upgrade path to Apache-Test when you need a more sophisticated testing framework. (To be fair, both Simple-Test and PHPUnit now also offer Apache-Test integration.)

Regarding functions in the global namespace, I can understand your hesitation. But, those who dislike such things are the ones least likely to encounter a collision, right? :-)

Anyway, glad to see someone else in the PHP community interested in testing. Thanks for helping to spread the word.

Thu, 26 Jan 2006 at 18:46:05 GMT Link

3.Pedro Cardoso said:

I think that the folowing does the same thing.

I am using it in a personal project and think it is a great tool.

It is class bases and the library is quite extensive.

Probably you all know about it but anyway, here it is:




Fri, 27 Jan 2006 at 09:58:08 GMT Link

4.Matt said:

Why not atleast create an class that could act as a namespace, and could also be instantiated thereby eliminating the globals? That seems like a good next step?


Wed, 22 Mar 2006 at 21:08:58 GMT Link

5.Chris Shiflett said:

Hi Matt,

I might do that, but people can always encapsulate this in a class themselves, as Nola has demonstrated.

The original intention was for the behavior to act as closely to Test::More as possible, and its success might be due to its extreme simplicity.

On the other hand, I do see the benefits of offering a class for this, one being that I could add it as a PEAR component.

Wed, 22 Mar 2006 at 21:14:17 GMT Link

6.Matt said:

Hey Chris, another thing that would be nice (if it were in a class) is to not print directly from each function, but to append the html/text to a variable and then do a report after it's done, printing the variables' content instead. That way, you could even use a seperate logger class (for example) and email the tests. I guess this could just be done with output buffering before the tests, but it'd be nice if it were built in. I understand that this is suppossed to be just like the perl version though. Anyway, I'm actually testing now! For the first time. :)

Thu, 23 Mar 2006 at 12:45:30 GMT Link

Hello! What’s your name?

Want to comment? Please connect with Twitter to join the discussion.