About the Author

Chris Shiflett

Chris Shiflett is an author and speaker who leads the web application security practice at OmniTI.


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 called test-more.php. 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:

<?php 

$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:

<?php 

$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 test-more.php:

<?php 

include './test-more.php';
include 
'./user-class.php';

plan(8);

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 user-class.php file to implement the methods she uses:

<?php 

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:

1..8
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 those lines being not ok instead of ok):

# Looks like you failed 1 tests of 8.

So, even without a testing framework, you can use test-more.php as a simple testing facility. If you want to try it yourself, you can download Apache-Test (it's bundled with the distribution), look at the very bottom of TestConfigPHP.pm, or grab it from my code repository:

P.S. Using Test::Harness To Test PHP Applications, a talk being given at PHP Quebec, is supposed to cover this same topic. Hopefully Ken is keeping up with what's going on. If so, it should be a good talk. If not, it will be disappointing. :-)

About This Post

Test::Simple for PHP was posted on Thu, 26 Jan 2006 at 16:33:01 GMT.

6 Comments

1. Nola's GravatarNola 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's GravatarChris 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's GravatarPedro 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:

http://www.lastcraft.com/

Regards

JP

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


4. Matt's GravatarMatt 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?

-matt

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


5. Chris Shiflett's GravatarChris 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's GravatarMatt 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


Post A Comment

Personal Details and Comment

Style Guide

Line breaks are converted to paragraphs. Also use:

  • <a href="" title="">text</a>1
  • <em>text</em>
  • <blockquote><p>text</p></blockquote>
  • <code>2  <?php  if ($foo) {      $foo = TRUE;  }  ?></code>
  1. Note: <code> can be used inline (e.g. in paragraphs) or in a block as shown. Include whitespace and newlines in blocks.

Please enter Chris (my first name) below. This is a primitive spam prevention technique, and I apologize for the inconvenience.

Preview and Submit

Upcoming Talks

PHP Appalachia

11 - 14 Oct 2008

At Big Bear Lodge, Gatlinburg, Tennessee.

php|works / PyWorks

12 - 14 Nov 2008

At Sheraton Gateway Hotel Atlanta Airport, Atlanta, Georgia.

New Comments

Chris Shiflett wrote:

Miguel, read the post again. PHP 4.4.9 is the final release of PHP 4.

Posted in End of Life for PHP 4
Miguel Palazzo wrote:

I think you're wrong. PHP 4.4 is DEAD, that's so right, because they just released 4.4.9, and you...

Posted in End of Life for PHP 4
alikim wrote:

Hi, Thanks for the article! Tell me please if it's enough to use just session_start(); se...

Posted in
Wayne wrote:

Hi ZX, When taking in data, you should always check to see if magic_quotes is enabled. If it i...

Posted in addslashes() Versus mysql_real_escape_string()
Chris Shiflett wrote:

Thanks, Brandon. I'm glad you liked the talk. Maybe some parts of it would be interesting to some...

Posted in ZendCon

Browse Comments