Skip to content

Constraints

elblinkin edited this page Jun 25, 2012 · 8 revisions

This is a tutorial for using https://github.com/etsy/phpunit-extensions/tree/master/PHPUnit/Extensions/Constraint.

Constraints are derived from Hamcrest matchers. Hamcrest is a framework for creating matchers, allowing match rules to be defined declaratively (see). In PHPUnit the two most common usages of constraints are:

PHPUnit_Extensions_Constraint_EqualsClosure

You may encounter a situation where you would like to use assertEquals to compare two object, but it turns out you only want to do so on a subset of fields. For example, that pesky ORM object that contains fields for transient (for lack of a better word) database connections.

Most will just add multiple assertions to the test, but then miss out on possibly valuable information from non-executed assertions. Some will do a bit better by writing the custom assertion, but will miss out on the value added by having a constraint.

Sadly, most miss out on constraints because it is yet another class, and if you are being rigorous, yet another file.

Since most custom assertions are checking equality of objects on a subset of fields, it seemed to make sense to create the EqualsClosure constraint. This way all you have to do is fill out a closure like it was that if statement in your custom assertion or constraint matches() function. Simple!

Example:

class UserAsserts {

    public static function equals($expected) {
        return new PHPUnit_Extensions_Constraint_EqualsClosure(
            $expected,
            function ($expected, $actual) {
                    return $expected->id === $actual->id
                        && $expected->first === $actual->first
                        && $expected->last === $actual->last;
            }
        );
    }

    public static function assertEquals($expected, $actual, $message='') {
        $this->assertThat(
            $actual,
            self::equals($expected),
            $message
        );
    }

    public static function assertNotEquals($expected, $actual, $message='') {
        $this->assertThat(
            $actual,
            new PHPUnit_Framework_Constraint_Not(
                self::equals($expected)
            ),
            $message
        );
    }
}

More Examples: https://github.com/etsy/phpunit-extensions/blob/master/Tests/Extensions/Constraint/EqualsClosureTest.php

PHPUnit_Extensions_Constraint_HasItems

This constraint requires that the actual array contains at least one of each of the expected items.

Example:

$object = $this->getMock('SomeClass')
    ->expects($this->any())
    ->method('doSomething')
    ->with(new PHPUnit_Extensions_Constraint_HasItems(array(1, 2, 3)));

...

// This will pass because we passed in an array that contains at least a 1, a 2, and a 3
$object->doSomething(array(4, 3, 2, 1));

// This will fail because we passed in an array that was missing a 1
$object->doSomething(array(3, 2, 0));

More Examples: https://github.com/etsy/phpunit-extensions/blob/master/Tests/Extensions/Constraint/HasItemsTest.php

PHPUnit_Extensions_Constraint_SameSize (Removed in v0.2.1)

Please use PHPUnit_Framework_Constraint_SameSize as PHPUnit 3.6

PHPUnit_Extensions_Constraint_StringMatchIgnoreWhitespace

This constraint allows verifying that the actual content of the string is as expected without needing to match leading or trailing whitespace, or having to get tabs and newlines correct.

Example:

$object = $this->getMock('SomeClass')
    ->expects($this->any())
    ->method('doSomething')
    ->with(new PHPUnit_Extensions_Constraint_StringMatchIgnoreWhitespace("spaces do not matter"));

...

// This will pass because the string after reducing white space are "spaces do not matter"
$object->doSomething("spaces\ndo\tnot matter ");

// This will fail because this string is NOT equivalent to "spaces do not matter"
$object->doSomething("but the not whitespace characters do!");

More Examples: https://github.com/etsy/phpunit-extensions/blob/master/Tests/Extensions/Constraint/StringMatchIgnoreWhitespaceTest.php

PHPUnit_Extensions_Constraint_ArrayHasKeyValuePair

This constraint requires that the actual array contains a particular key and value pair.

Example:

$object = $this->getMock('SomeClass')
    ->expects($this->any())
    ->method('doSomething')
    ->with(new PHPUnit_Extensions_Constraint_ArrayHasKeyValuePair('key', 'value'));

...

// This will pass because we passed in an array that contains at least a 1, a 2, and a 3
$object->doSomething(array('key' => 'value');

// This will fail because we passed in that does not pair 'key' with 'value'.
$object->doSomething(array('key' => 'not_value', 'not_key' => 'value'));

More Examples: https://github.com/etsy/phpunit-extensions/blob/master/Tests/Extensions/Constraint/ArrayHasKeyValuePairTest.php