Page 1 of 1

Peewee

Posted: Sat Oct 06, 2007 3:47 pm
by Ollie Saunders
I wrote this about a month ago. I was going to finish the mock object support but I still haven't got round to it so I'm setting it up on Google code anyway. There's a User manual in HTML in the repo if you check it out.

If you would like to have a philosophical discussion about the direction I should take it in I'd be most open to that.

Posted: Sat Oct 06, 2007 4:39 pm
by Christopher
Cool ... I just grabbed the files. I'll take a look at it.

Posted: Sun Oct 07, 2007 8:44 am
by Maugrim_The_Reaper
Being on the same page ;).

Myself and Travis S wicegood are also working on some new/revised testing/specing frameworks. You should run a search for PHPSpec (a behavour driven development framework based on rspec), PHPMock and there's rumour of a revised PHPT style setting also ;).I'm working primarily on PHPSpec (met it while writing Ruby way back when), and I expect an initial lightweight release in a few weeks (requesting a review before then from what's in svn a week from now). I'll also be looking into some TestNG style options. We're aimed at least partly on avoiding File based setup (e.g. PHPUnit's AllTests.php) in favour of a directory iterator and detect solution.

There could be points in this (e.g. PHPMock) where collaboration could benefit both of us. Travis and I are keen to have an independent Mock Object framework not tied in to any one framework. As far as I know only SimpleTest has a really good Mocking solution so far (PHPUnit's doesn't seem all that great to date - maybe when it's better documented and tested).

I'm downloading the code for a look - I think a lightweight unit testing library would be quite welcome in PHP and best of luck with it!

Posted: Mon Oct 08, 2007 1:55 pm
by Ollie Saunders
There could be points in this (e.g. PHPMock) where collaboration could benefit both of us.
I tell you what. In the interest of not flooding the market with stuff and ultimate community benefit. why don't I just discontinue development of peewee (it has been that way for a month already anyway) and help you guys out with PHPMock then. I am I right in thinking you've no source just for PHPMock? I couldn't see any in the svn browser.
Travis and I are keen to have an independent Mock Object framework not tied in to any one framework.
Sounds like an excellent idea to me.
As far as I know only SimpleTest has a really good Mocking solution so far
Hang on, I thought you both you and Travis are involved in the using more PHP 5 and re-writing the mock objects for SimpleTest? And now your going off and starting your own framework as well?

Posted: Mon Oct 08, 2007 3:40 pm
by Luke
Well with the limited experience that I do have with unit testing, I'm not really satisfied with what is out there (for PHP). I'd love to see some other libraries enter the market (or at least improvement on the ones that exist already)

Posted: Tue Oct 09, 2007 7:05 am
by Jenk
The object model I have created for smalltalk mock objects make use of expectations, so that the construct of the mock object appears along the lines of (loosely translated to php):

Code: Select all

$mock = new MockObject('SomeClass');
$expectSomeMethod = $mock->expectCall('SomeMethod');
$expectSomeMethod->return('foovalue', 1); // returns 'foovalue' on the first call
$expectSomeMethod->returnDefault(null); // return null on all calls without specified return value
$expectSomeMethod->expectNumberOfCalls('SomeMethod', 5); // expect 5 calls to SomeMethod()

$object->setSomeClass($mock);
$object->doSomething();
$this->should($mock->evaluate()); // evalute on MockObject iterates through all expectations and calls evalutate() on each, which in turn validates behaviour of the expectation.
There are also convenience methods for passing an array of return values to the expectation, to save calling return() many times :)

I can also specify the methods manually, so I don't have to use a specification:

Code: Select all

$mock = new MockObject();
$mock->addMethod('SomeMethod');
Just an insight in case you guys may be looking for ideas/user stories :)

Posted: Tue Oct 09, 2007 10:26 am
by Maugrim_The_Reaper
I tell you what. In the interest of not flooding the market with stuff and ultimate community benefit. why don't I just discontinue development of peewee (it has been that way for a month already anyway) and help you guys out with PHPMock then. I am I right in thinking you've no source just for PHPMock? I couldn't see any in the svn browser.
Well, you can grab us on the PHPSpec-Devel mailing list - http://www.phpspec.org redirects to our Google page.

I wouldn't actually ask you stop peewee development. There is quite a bit of room around for alternate (Unit/Other) Testing libraries. So the niche is fair game ;). PHPMock is different from a testing/specing framework in that it focuses on just the one thing - mocking and self-validation. I'd certainly love to have someone take charge on it - at the moment I'm stuck on PHPSpec alone (we have our first two iterations set up for development), so catch up with me on the mailing list and we'll string some Mocking ideas around.

You're right in that we have no code for PHPMock yet, it was literally start PHPSpec, wonder if a Mocking library existed, finding it didn't, and off went PHPMock to Google Code. We haven't had time to do any planning for it yet so your timing would be impeccable :).
Hang on, I thought you both you and Travis are involved in the using more PHP 5 and re-writing the mock objects for SimpleTest? And now your going off and starting your own framework as well?
We're both SimpleTest users and developers/maintainers/infrequent bug solvers actually ;). Travis is currently working towards the SimpleTest migration to subversion before the PHP5 fest starts. I think the reasoning for working on two or more frameworks is actually not as conflicting as you think.

SimpleTest, as far as I'm concerned, is the best TDD friendly UT framework existing for PHP (PHPUnit likes to think it is for some reason ;)). But we both also want a BDD framework. In fact we both also use the PHPT framework! ;) So we're jumping from tool to tool depending on any number of reasons. Personal preference, whether testing or TDD'ing, form of testing (Selenium/WebTests/Unit/Integration), current project standards (ZF requires PHPUnit - bleh!). PHPSpec is currently TDD'd using phpt even.

Anyway, after nattering on for too many words (again) - get onto the PHPSpec mailing list ;). Keep peewee going as you wish - I would never suggest stopping development on something new and fresh.

Posted: Tue Oct 09, 2007 7:44 pm
by Ollie Saunders
Uhhh, I don't know any more. I'm not even sure I'm going to be writing PHP for that much longer. I'm considering enforcing a personal rule of only maintaining existing things. Of course that could mean I'm still using it for at least a year. You made a lot of sense with what you say there Maugrim and I do like Peewee, I'm just very unsure about where to take it. There's only so much you can do with minimalism. I should start by documenting the API.

Anyway, I got the opportunity to use Peewee in a bit of a server test here. Also I wrote this in a way so as to test the tests would fail incorrect data which is not something I've done before. I enclose the code for your interest:

run.php

Code: Select all

<?php
require_once 'peewee/peewee.php';
class Evil
{
    protected function _randomElement($array)
    {
        return array_slice($array, mt_rand(0, count($array)), 1);
    }
}
abstract class ServerTestCase extends Peewee_UnitTestCase
{
    private $_isEvil;
    public function __construct($isEvil = false)
    {
        $this->_isEvil = $isEvil;
    }
    final public function setUp()
    {
        if ($this->_isEvil) {
            $this->setUpEvil();
        } else {
            $this->setUpNice();
        }
        $this->_secondrySetup();
    }
    public function setUpEvil() {}
    public function setUpNice() {}
    protected function _secondrySetup() {}
}
foreach (glob('test*.php') as $testFile) {
    require_once $testFile;
}
/**
 * Runs tests in a nice and evil way and shows the discrepencies
 */
function runTests()
{
    // numbers of passes for each test need to be records because the
    // evil versions should have that many failures
    $passCounts = array();
    // runs all the test cases in nice mode
    foreach (Peewee_Runner::getDefinedTestCases() as $testCase) {
        $testCase->run();
        $passCounts[get_class($testCase)] = $testCase->getCounter()->get('pass');
    }
    // runs all the test cases in evil mode
    foreach (get_declared_classes() as $class) {
        if (strpos($class, 'Evil') === 0 && strlen($class) > 4) {
            $caseName = 'Test' . substr($class, strlen('Evil'));
            $case = new $caseName(true);
            ob_start();
            $case->run(); // won't need to show output if there aren't discrepencies
            $output = ob_get_contents();
            ob_end_clean();
            $failures = $case->getCounter()->get('fail');
            if ($failures !== $passCounts[$caseName]) {
                // differences found
                echo "Expected to find {$passCounts[$caseName]} failures from evil case but found $failures:\n";
                echo " >>>> \n$output <<<<\n\n";
            }
        }
    }
    echo array_sum($passCounts), " passes\n";
}
runTests();
testVersions.php

Code: Select all

<?php
interface Versions_Interface
{
    function getIssueName();
    function getIssueVersion();
    function getPhpVersion();
    function getApacheVersion();
}
class Versions implements Versions_Interface
{
    const VERSION_REGEX = '~(\d+\.?)+~';
    const ISSUE_FILENAME = '/etc/issue.net';
    private function _getIssueParts()
    {
        if (!is_readable(self::ISSUE_FILENAME)) {
            throw new Exception('Unable to read issue file ' . (file_exists(self::ISSUE_FILENAME) ?  'but does' : 'and does not') . ' exist');
        }
        return preg_split('~\s+~', trim(file_get_contents(self::ISSUE_FILENAME)), -1, PREG_SPLIT_NO_EMPTY);
    }
    public function getIssueName()
    {
        list($issue) = $this->_getIssueParts();
        return strtolower($issue);
    }
    public function getIssueVersion()
    {
        foreach ($this->_getIssueParts() as $part) {
            if (preg_match(self::VERSION_REGEX, $part)) {
                return $part;
            }
        }
        throw new Exception('Could not find version data in issue file (' . self::ISSUE_FILENAME . ')');
    }
    public function getPhpVersion()
    {
        return PHP_VERSION;
    }
    public function getApacheVersion()
    {
        preg_match('~(\d+\.?)+~', `apache2ctl -v | grep version`, $matches);
        return $matches[0];
    }
}
// All/any of these should cause failures in the tests, if they don't we'll hear about it
class Evil_Versions extends Evil implements Versions_Interface
{
    public function getIssueName()
    {
        return $this->_randomElement(array('Debian', 'ubun', 'Ubun'));
    }
    public function getIssueVersion()
    {
        return $this->_randomElement(array('6.11', '6.09', '7.0'));
    }
    public function getPhpVersion()
    {
        return $this->_randomElement(array('5.2.2', '5.2.4', '2'));
    }
    public function getApacheVersion()
    {
        return $this->_randomElement(array('2.1', '2.054', '1.9', '2.2'));
    }
}
class Test_Versions extends ServerTestCase
{
    private $_vers;
    public function setUpNice()
    {
        $this->_vers = new Versions();
    }
    public function setUpEvil()
    {
        $this->_vers = new Evil_Versions();
    }
    public function testUbuntu610()
    {
        $this->assertEqual($this->_vers->getIssueName(), 'ubuntu');
        $this->assertEqual($this->_vers->getIssueVersion(), '6.10');
    }
    public function testPhpVersion()
    {
        $this->assertEqual($this->_vers->getPhpVersion(), '5.2.3');
    }
    public function testApache20()
    {
        $this->assertTrue(
            version_compare($this->_vers->getApacheVersion(), '2.0.55') >= 0 &&
            version_compare($this->_vers->getApacheVersion(), '2.1') < 0
        );
    }
}
Seems like a hell of a lot of code for very simple checks but they couldn't be much more thorough or strong. Some of these things could make it into the standard peewee.php - Evil objects, sounds good doesn't it :)