Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

New constraint 'callback' for complex assertions. #206

Closed
wants to merge 1 commit into from

3 participants

@trapp

Hi,

I've created a new constraint for matching against a callable. The reason for this are some limitations I ran into by mocking objects.

Imagine a method under test creates an object containing another object and you want to check the existance of both.

$object1 = new Object1();
$object1->setChild(new Object2('some property'));
$db->insert('TableName', $object1);

The test code for this would be something like:

// Create mock of database
$db = $this->getMock('SomeDatabaseClass');
// Set up expectations.
$db->expects($this->once())
     ->method('insert')
     ->with(
           $this->equalTo('TableName'),
           // Problem! How to check class of $object2 and value of $object1->getChild()->getProperty()?
        );

Is this a valid problem or is there a solution for this I just don't see.

This pull request solves this problem by accepting callbacks (including closures since php 5.3) as constraints:

// Create mock of database
$db = $this->getMock('SomeDatabaseClass');
// Set up expectations.
$db->expects($this->once())
   ->method('insert')
   ->with(
        $this->equalTo('TableName'),
        $this->callback(
            function ($object) {
                // Check for objects existance...
                // ...
                // Check value
                return $object->getChild()->getProperty() == 'some property';
            }
        )
    );

With php 5.3 one can use closures as in the example. Earlier versions of php can still use this feature using normal callbacks like array($object, 'method');

What do you think about this?

@lstrojny

Nice!

@edorian edorian closed this pull request from a commit
@edorian edorian Closes #206: Fixes, cleanup, changelog, adaption and more tests for t…
…he merged "callback constraint"
c2b43df
@edorian edorian closed this in c2b43df
@greglamb greglamb referenced this pull request from a commit in greglamb/phpunit
@edorian edorian Closes #206: Fixes, cleanup, changelog, adaption and more tests for t…
…he merged "callback constraint"
89fa9d3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 17, 2011
  1. @trapp
This page is out of date. Refresh to see the latest.
View
10 PHPUnit/Framework/Assert.php
@@ -2169,6 +2169,16 @@ public static function isTrue()
{
return new PHPUnit_Framework_Constraint_IsTrue;
}
+
+ /**
+ * Returns a PHPUnit_Framework_Constraint_Callback matcher object.
+ *
+ * @return PHPUnit_Framework_Constraint_Callback
+ */
+ public static function callback($callback)
+ {
+ return new PHPUnit_Framework_Constraint_Callback($callback);
+ }
/**
* Returns a PHPUnit_Framework_Constraint_IsFalse matcher object.
View
10 PHPUnit/Framework/Assert/Functions.php
@@ -1587,6 +1587,16 @@ function isTrue()
}
/**
+ * Returns a PHPUnit_Framework_Constraint_Callback matcher object.
+ *
+ * @return PHPUnit_Framework_Constraint_Callback
+ */
+function callback()
+{
+ return PHPUnit_Framework_Assert::callback();
+}
+
+/**
* Returns a PHPUnit_Framework_Constraint_IsType matcher object.
*
* @param string $type
View
100 PHPUnit/Framework/Constraint/Callback.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * PHPUnit
+ *
+ * Copyright (c) 2002-2011, Sebastian Bergmann <sebastian@phpunit.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package PHPUnit
+ * @subpackage Framework_Constraint
+ * @author Sebastian Bergmann <sebastian@phpunit.de>
+ * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @link http://www.phpunit.de/
+ */
+
+/**
+ * Constraint that evaluates against a specified closure.
+ *
+ * @package PHPUnit
+ * @subpackage Framework_Constraint
+ * @author Sebastian Bergmann <sebastian@phpunit.de>
+ * @author Timon Rapp <timon@zaeda.net>
+ * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version Release: @package_version@
+ * @link http://www.phpunit.de/
+ */
+class PHPUnit_Framework_Constraint_Callback extends PHPUnit_Framework_Constraint
+{
+ private $callback;
+
+ /**
+ * @param Callback|Closure $value
+ * @throws InvalidArgumentException
+ */
+ public function __construct($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new InvalidArgumentException(
+ sprintf(
+ 'Callback specified for PHPUnit_Framework_Constraint_Callback <%s> ' .
+ 'is not callable.',
+ $callback
+ )
+ );
+ }
+ $this->callback = $callback;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $value. Returns TRUE if the
+ * constraint is met, FALSE otherwise.
+ *
+ * @param mixed $value Value or object to evaluate.
+ * @return bool
+ */
+ public function evaluate($value = null)
+ {
+ return call_user_func($this->callback, $value);
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return 'is accepted by specified callback';
+ }
+}
View
69 Tests/Framework/ConstraintTest.php
@@ -1167,6 +1167,75 @@ public function testConstraintLessThanOrEqual()
$this->fail();
}
+
+ /**
+ * @covers PHPUnit_Framework_Constraint_Callback
+ */
+ public function testConstraintCallback()
+ {
+ // Test closures. Requires PHP 5.3.
+ $closureReflect = function($parameter) {
+ return $parameter;
+ };
+
+ $closureWithoutParameter = function() {
+ return true;
+ };
+
+ $constraint = PHPUnit_Framework_Assert::callback($closureWithoutParameter);
+ $this->assertTrue($constraint->evaluate());
+
+ $constraint = PHPUnit_Framework_Assert::callback($closureReflect);
+ $this->assertTrue($constraint->evaluate(true));
+ $this->assertFalse($constraint->evaluate(false));
+
+ // Test callbacks.
+ $helperConstraint = PHPUnit_Framework_Assert::isTrue();
+ $callback = array($helperConstraint, 'evaluate');
+
+ $constraint = PHPUnit_Framework_Assert::callback($callback);
+ $this->assertTrue($constraint->evaluate(true));
+ $this->assertFalse($constraint->evaluate(false));
+
+ $this->assertEquals('is accepted by specified callback', $constraint->toString());
+
+ try {
+ $constraint->fail(true, '');
+ }
+
+ catch (PHPUnit_Framework_ExpectationFailedException $e) {
+ $this->assertEquals(
+ 'Failed asserting that <boolean:true> is accepted by specified callback.',
+ $e->getDescription()
+ );
+
+ return;
+ }
+
+ $this->fail();
+ }
+
+ /**
+ * @covers PHPUnit_Framework_Constraint_Callback
+ */
+ public function testConstraintCallbackInvalidArgument()
+ {
+
+ try {
+ $constraint = PHPUnit_Framework_Assert::callback('invalid callback');
+ }
+
+ catch (InvalidArgumentException $e) {
+ $this->assertEquals(
+ 'Callback specified for PHPUnit_Framework_Constraint_Callback <invalid callback> is not callable.',
+ $e->getMessage()
+ );
+
+ return;
+ }
+
+ $this->fail();
+ }
/**
* @covers PHPUnit_Framework_Constraint_IsEqual
Something went wrong with that request. Please try again.