Pages

12/12/2012

Comparing TDD/BDD Framework for PHP

Comparing TDD/BDD Framework for PHP
 - TDD = Test Driven Development
 - BDD = Behavior Driven Development

This comparison focusing on unit-testing (testing at class/method level).
Browser integration feature is not in this scope

Type PHPUnit PHPUnit-Story PHPSpec PHPSpec2 Spectrum
Syntax
assertEquals('word', $wrapper->wrap('word', 5));
	$this->given('New game')
	     ->when('Player rolls', 5)
	     ->and('Player rolls', 5)
	     ->and('Player rolls', 3)
	     ->then('Score should be', 16);

	but actually use this internally:
		$this->assertEquals($arguments[0], $world['game']->score());
$this->spec($this->_bowling->score)->should->equal(0);
$this->getPayment()->getType()->shouldReturn(“visa”);
verify($person->firstName, '==', 'Bob');
Example Code Block from http://www.phpunit.de/manual/3.3/en/phpunit-book.html Example 13.1
<?php
require_once 'PHPUnit/Framework.php';
require_once 'BankAccount.php';
 
class BankAccountTest extends PHPUnit_Framework_TestCase
{
    protected $ba;
 
    protected function setUp()
    {
        $this->ba = new BankAccount;
    }
 
    public function testBalanceIsInitiallyZero()
    {
        $this->assertEquals(0, $this->ba->getBalance());
    }
 
    public function testBalanceCannotBecomeNegative()
    {
        try {
            $this->ba->withdrawMoney(1);
        }
 
        catch (BankAccountException $e) {
            $this->assertEquals(0, $this->ba->getBalance());
 
            return;
        }
 
        $this->fail();
    }
 
    public function testBalanceCannotBecomeNegative2()
    {
        try {
            $this->ba->depositMoney(-1);
        }
 
        catch (BankAccountException $e) {
            $this->assertEquals(0, $this->ba->getBalance());
 
            return;
        }
 
        $this->fail();
    }
}
?>
from http://sebastian-bergmann.de/archives/738-Support-for-BDD-and-Stories-in-PHPUnit-3.3.html
<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
 
require_once 'BowlingGame.php';
 
class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase
{
    /**
     * @scenario
     */
    public function scoreForOneSpareIs16()
    {
        $this->given('New game')
             ->when('Player rolls', 5)
             ->and('Player rolls', 5)
             ->and('Player rolls', 3)
             ->then('Score should be', 16);
    }
 
    public function runGiven(&$world, $action, $arguments)
    {
        switch($action) {
            case 'New game': {
                $world['game']  = new BowlingGame;
                $world['rolls'] = 0;
            }
            break;
 
            default: {
                return $this->notImplemented($action);
            }
        }
    }
 
    public function runWhen(&$world, $action, $arguments)
    {
        switch($action) {
            case 'Player rolls': {
                $world['game']->roll($arguments[0]);
                $world['rolls']++;
            }
            break;
 
            default: {
                return $this->notImplemented($action);
            }
        }
    }
 
    public function runThen(&$world, $action, $arguments)
    {
        switch($action) {
            case 'Score should be': {
                for ($i = $world['rolls']; $i < 20; $i++) {
                    $world['game']->roll(0);
                }
 
                $this->assertEquals($arguments[0], $world['game']->score());
            }
            break;
 
            default: {
                return $this->notImplemented($action);
            }
        }
    }
}
?>
from https://github.com/phpspec/phpspec
<?php
class DescribeNewBowlingGame extends \PHPSpec\Context
{

    private $_bowling;

    public function before()
    {
        $this->_bowling = new Bowling;
    }

    public function itShouldScore0ForGutterGame()
    {
        for ($i=1; $i<=20; $i++) {
            $this->_bowling->hit(0); // someone is really bad at bowling!
        }
        $this->spec($this->_bowling->score)->should->equal(0);
    }

}
from http://phpspec.net/
<?php

namespace spec;

use PHPSpec2\ObjectBehavior;

class Markdown extends ObjectBehavior
{
    function it_should_be_initializable()
    {
        $this->shouldHaveType('Markdown');
    }

    function it_converts_plain_text_to_html_paragraphs()
    {
        $this->toHtml("Hi, there")->shouldReturn("<p>Hi, there</p>");
    }

    public function toHtml()
    {
        return "<p>Hi, there</p>";
    }
}
from https://bitbucket.org/mkharitonov/spectrum/overview
<?php
require_once __DIR__ . '/spectrum/init.php';

describe('AddressBook', function(){
    beforeEach(function(){
        world()->addressBook = new AddressBook();
    });

    context('"MySql" driver', function(){
        beforeEach(function(){
            world()->addressBook->setDriver(new drivers\MySql());
        });
    });

    context('"Files" driver', function(){
        beforeEach(function(){
            world()->addressBook->setDriver(new drivers\Files());
        });
    });

    it('Should find person by first name', function(){
        $person = world()->addressBook->findPerson('Bob');
        verify($person->firstName, '==', 'Bob');
    });

    it('Should find person by phone number in any format', array(
        '+7 (495) 123-456-7',
        '(495) 123-456-7',
        '123-456-7',
    ), function($phoneNumber){
        $person = world()->addressBook->findPerson($phoneNumber);
        verify($person->phoneNumber, '==', '+74951234567');
    });
});

\spectrum\RootDescribe::run();
Matchers from phpunit/PHPUnit/Framework/Assert/Functions.php
  • any()
  • anything()
  • arrayHasKey($key)
  • assertArrayHasKey($key, array $array,
  • $message = '')
  • assertArrayNotHasKey($key, array $array,
  • $message = '')
  • assertAttributeContains($needle,
  • $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE)
  • assertAttributeContainsOnly($type,
  • $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '')
  • assertAttributeCount($expectedCount,
  • $haystackAttributeName, $haystackClassOrObject, $message = '')
  • assertAttributeEmpty(
  • $haystackAttributeName, $haystackClassOrObject, $message = '')
  • assertAttributeEquals($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertAttributeGreaterThan($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '')
  • assertAttributeGreaterThanOrEqual(
  • $expected, $actualAttributeName, $actualClassOrObject, $message = '')
  • assertAttributeInstanceOf($expected,
  • $attributeName, $classOrObject, $message = '')
  • assertAttributeInternalType($expected,
  • $attributeName, $classOrObject, $message = '')
  • assertAttributeLessThan($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '')
  • assertAttributeLessThanOrEqual($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '')
  • assertAttributeNotContains($needle,
  • $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE)
  • assertAttributeNotContainsOnly($type,
  • $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '')
  • assertAttributeNotCount($expectedCount,
  • $haystackAttributeName, $haystackClassOrObject, $message = '')
  • assertAttributeNotEmpty(
  • $haystackAttributeName, $haystackClassOrObject, $message = '')
  • assertAttributeNotEquals($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertAttributeNotInstanceOf($expected,
  • $attributeName, $classOrObject, $message = '')
  • assertAttributeNotInternalType($expected,
  • $attributeName, $classOrObject, $message = '')
  • assertAttributeNotSame($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '')
  • assertAttributeSame($expected,
  • $actualAttributeName, $actualClassOrObject, $message = '')
  • assertClassHasAttribute($attributeName,
  • $className, $message = '')
  • assertClassHasStaticAttribute(
  • $attributeName, $className, $message = '')
  • assertClassNotHasAttribute($attributeName,
  • $className, $message = '')
  • assertClassNotHasStaticAttribute(
  • $attributeName, $className, $message = '')
  • assertContains($needle, $haystack,
  • $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE)
  • assertContainsOnly($type, $haystack,
  • $isNativeType = NULL, $message = '')
  • assertCount($expectedCount, $haystack,
  • $message = '')
  • assertEmpty($actual, $message = '')
  • assertEqualXMLStructure(DOMElement
  • $expectedElement, DOMElement $actualElement, $checkAttributes = FALSE, $message = '')
  • assertEquals($expected, $actual, $message
  • = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertFalse($condition, $message = '')
  • assertFileEquals($expected, $actual,
  • $message = '', $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertFileExists($filename, $message = '')
  • assertFileNotEquals($expected, $actual,
  • $message = '', $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertFileNotExists($filename, $message =
  • '')
  • assertGreaterThan($expected, $actual,
  • $message = '')
  • assertGreaterThanOrEqual($expected,
  • $actual, $message = '')
  • assertInstanceOf($expected, $actual,
  • $message = '')
  • assertInternalType($expected, $actual,
  • $message = '')
  • assertJsonStringEqualsJsonString(
  • $expectedJson, $actualJson, $message = '')
  • assertJsonStringNotEqualsJsonString(
  • $expectedJson, $actualJson, $message = '')
  • assertJsonStringEqualsJsonFile(
  • $expectedFile, $actualJson, $message = '')
  • assertJsonStringNotEqualsJsonFile(
  • $expectedFile, $actualJson, $message = '')
  • assertJsonFileNotEqualsJsonFile(
  • $expectedFile, $actualFile, $message = '')
  • assertJsonFileEqualsJsonFile(
  • $expectedFile, $actualFile, $message = '')
  • assertLessThan($expected, $actual,
  • $message = '')
  • assertLessThanOrEqual($expected, $actual,
  • $message = '')
  • assertNotContains($needle, $haystack,
  • $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE)
  • assertNotContainsOnly($type, $haystack,
  • $isNativeType = NULL, $message = '')
  • assertNotCount($expectedCount, $haystack,
  • $message = '')
  • assertNotEmpty($actual, $message = '')
  • assertNotEquals($expected, $actual,
  • $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertNotInstanceOf($expected, $actual,
  • $message = '')
  • assertNotInternalType($expected, $actual,
  • $message = '')
  • assertNotNull($actual, $message = '')
  • assertNotRegExp($pattern, $string,
  • $message = '')
  • assertNotSame($expected, $actual, $message
  • = '')
  • assertNotSameSize($expectedCount,
  • $haystack, $message = '')
  • assertNotTag($matcher, $actual, $message =
  • '', $isHtml = TRUE)
  • assertNull($actual, $message = '')
  • assertObjectHasAttribute($attributeName,
  • $object, $message = '')
  • assertObjectNotHasAttribute(
  • $attributeName, $object, $message = '')
  • assertRegExp($pattern, $string, $message =
  • '')
  • assertSame($expected, $actual, $message =
  • '')
  • assertSameSize($expected, $actual,
  • $message = '')
  • assertSelectCount($selector, $count,
  • $actual, $message = '', $isHtml = TRUE)
  • assertSelectEquals($selector, $content,
  • $count, $actual, $message = '', $isHtml = TRUE)
  • assertSelectRegExp($selector, $pattern,
  • $count, $actual, $message = '', $isHtml = TRUE)
  • assertStringEndsNotWith($suffix, $string,
  • $message = '')
  • assertStringEndsWith($suffix, $string,
  • $message = '')
  • assertStringEqualsFile($expectedFile,
  • $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertStringMatchesFormat($format,
  • $string, $message = '')
  • assertStringMatchesFormatFile($formatFile,
  • $string, $message = '')
  • assertStringNotEqualsFile($expectedFile,
  • $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE)
  • assertStringNotMatchesFormat($format,
  • $string, $message = '')
  • assertStringNotMatchesFormatFile(
  • $formatFile, $string, $message = '')
  • assertStringStartsNotWith($prefix,
  • $string, $message = '')
  • assertStringStartsWith($prefix, $string,
  • $message = '')
  • assertTag($matcher, $actual, $message =
  • '', $isHtml = TRUE)
  • assertThat($value,
  • PHPUnit_Framework_Constraint $constraint, $message = '')
  • assertTrue($condition, $message = '')
  • assertXmlFileEqualsXmlFile($expectedFile,
  • $actualFile, $message = '')
  • assertXmlFileNotEqualsXmlFile(
  • $expectedFile, $actualFile, $message = '')
  • assertXmlStringEqualsXmlFile(
  • $expectedFile, $actualXml, $message = '')
  • assertXmlStringEqualsXmlString(
  • $expectedXml, $actualXml, $message = '')
  • assertXmlStringNotEqualsXmlFile(
  • $expectedFile, $actualXml, $message = '')
  • assertXmlStringNotEqualsXmlString(
  • $expectedXml, $actualXml, $message = '')
  • at($index)
  • atLeastOnce()
  • attribute(PHPUnit_Framework_Constraint
  • $constraint, $attributeName)
  • attributeEqualTo($attributeName, $value,
  • $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
  • classHasAttribute($attributeName)
  • classHasStaticAttribute($attributeName)
  • contains($value, $checkForObjectIdentity =
  • TRUE)
  • containsOnly($type)
  • equalTo($value, $delta = 0, $maxDepth =
  • 10, $canonicalize = FALSE, $ignoreCase = FALSE)
  • exactly($count)
  • fileExists()
  • greaterThan($value)
  • greaterThanOrEqual($value)
  • identicalTo($value)
  • isEmpty()
  • isFalse()
  • isInstanceOf($className)
  • isNull()
  • isTrue()
  • callback($callback)
  • isType($type)
  • lessThan($value)
  • lessThanOrEqual($value)
  • logicalAnd()
  • logicalNot(PHPUnit_Framework_Constraint
  • $constraint)
  • logicalOr()
  • logicalXor()
  • matches($string)
  • matchesRegularExpression($pattern)
  • never()
  • objectHasAttribute($attributeName)
  • onConsecutiveCalls()
  • once()
  • returnArgument($argumentIndex)
  • returnCallback($callback)
  • returnSelf()
  • returnValue($value)
  • returnValueMap(array $valueMap)
  • stringContains($string, $case = TRUE)
  • stringEndsWith($suffix)
  • stringStartsWith($prefix)
  • throwException(Exception $exception)
same as PHPUnit
  • be($expected)
  • equal($expected)
  • beEqualTo($expected)
  • beAnInstanceOf($expected)
  • beSet($expected)
  • beArray($expected)
  • beObject($expected)
  • beString($expected)
  • beInt($expected)
  • beFloat($expected)
  • beEmpty($expected)
  • beNull($expected)
  • beFalse($expected)
  • beTrue($expected)
  • beGreaterThanOrEqualTo($expected)
  • beGreaterThan($expected)
  • beLessThanOrEqualTo($expected)
  • beLessThan($expected)
  • containText($expected)
  • haveKey($expected)
  • customMatcher($expected)
  • predecate - ex. beClass,beAClass,beAnClass,haveName,haveAName,haveAnName
  • throwException
In src/PHPSpec2/Matcher
  • BasicMatcher.php
    • positiveMatch($name, $subject, array $arguments)
    • negativeMatch($name, $subject, array $arguments)
    • matches($subject, array $arguments)
    • getFailureException($name, $subject, array $arguments)
    • getNegativeFailureException($name, $subject, array $arguments)
  • ComparisionMatcher.php
    • beLike($subject, array $arguments) : { $subject==$arguments[0]}
  • CountMatcher.php
    • haveCount($subject, array $arguments) : {$arguments[0] === count($subject)}
  • IdentityMatcher
    • return($subject, array $arguments) : {$subject === $arguments[0]}
    • be($subject, array $arguments) : {$subject === $arguments[0]}
    • equal($subject, array $arguments) : {$subject === $arguments[0]}
    • beEqualTo($subject, array $arguments) : {$subject === $arguments[0]}
  • InlineMatcher.php
  • MatchersCollection.php
  • ObjectStateMatcher.php
    • beAbstract
    • beSimple
    • beUserDefined
    • beFinal
    • haveProperty
    • haveAnything
    • haveMethod
    • haveProperty
  • ScalarMatcher.php
    • is_bool
    • beInt
    • beFloat
    • beString
    • beBoolean
  • ThrowMatcher.php
    • throw
  • TypeMatcher.php
    • beAnInstanceOf($subject, array $arguments) : {(null !== $subject) && ($subject instanceof $arguments[0])}
    • returnAnInstanceOf($subject, array $arguments) : {(null !== $subject) && ($subject instanceof $arguments[0])}
    • haveType($subject, array $arguments) : {(null !== $subject) && ($subject instanceof $arguments[0])}
    • implement($subject, array $arguments) : {(null !== $subject) && ($subject instanceof $arguments[0])}
  • eq
  • false
  • gt
  • gte
  • ident : (use ===)
  • instanceofMatcher
  • lt
  • lte
  • null
  • throwException
  • true
Installation
  • PEAR:
    pear config-set auto_discover 1
    pear install pear.phpunit.de/PHPUnit
  • Composer: "phpunit/phpunit" : "3.7.10"
    {
        "require-dev": {
            "phpunit/phpunit": "3.7.*"
        }
    }
  • PHP Archive(PHAR)
    wget http://pear.phpunit.de/get/phpunit.phar
    chmod +x phpunit.phar
Last Update
(from 2012-12-12)
2012-12-10 2012-10-05 2012-09-08 2012-10-08 2012-11-13
Documentation/Example Document: http://www.phpunit.de/manual/3.7/en/index.html (English, French, Japanese) Document/Example: http://www.phpunit.de/manual/current/en/behaviour-driven-development.html (English, French, Japanese) No online document! (To read it compile it from /doc from source from github) Document: http://phpspec.net/#manual Document: http://mkharitonov.net/spectrum/ (old and only russian)
Example: http://spectrum-framework.org/ (English+Live Result)

No comments:

Post a Comment