diff --git a/src/Expectation.php b/src/Expectation.php index 255c436b..879f7131 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -170,11 +170,20 @@ final class Expectation /** * Asserts that the value contains the property $name. + * + * @param mixed $value */ - public function toHaveProperty(string $name): Expectation + public function toHaveProperty(string $name, $value = null): Expectation { + $this->toBeObject(); + Assert::assertTrue(property_exists($this->value, $name)); + if (func_num_args() > 1) { + /* @phpstan-ignore-next-line */ + Assert::assertEquals($value, $this->value->{$name}); + } + return $this; } @@ -460,6 +469,21 @@ final class Expectation return $this; } + /** + * Asserts that the value object matches a subset + * of the properties of an given object. + * + * @param array|object $object + */ + public function toMatchObject($object): Expectation + { + foreach ((array) $object as $property => $value) { + $this->toHaveProperty($property, $value); + } + + return $this; + } + /** * Dynamically calls methods on the class without any arguments. * diff --git a/tests/Expect/toHaveProperty.php b/tests/Expect/toHaveProperty.php index a7c0c649..19b4c92e 100644 --- a/tests/Expect/toHaveProperty.php +++ b/tests/Expect/toHaveProperty.php @@ -2,11 +2,15 @@ use PHPUnit\Framework\ExpectationFailedException; -$obj = new stdClass(); -$obj->foo = 'bar'; +$obj = new stdClass(); +$obj->foo = 'bar'; +$obj->fooNull = null; test('pass', function () use ($obj) { expect($obj)->toHaveProperty('foo'); + expect($obj)->toHaveProperty('foo', 'bar'); + expect($obj)->toHaveProperty('fooNull'); + expect($obj)->toHaveProperty('fooNull', null); }); test('failures', function () use ($obj) { diff --git a/tests/Expect/toMatchObject.php b/tests/Expect/toMatchObject.php new file mode 100644 index 00000000..fd2c358b --- /dev/null +++ b/tests/Expect/toMatchObject.php @@ -0,0 +1,31 @@ +user = (object) [ + 'id' => 1, + 'name' => 'Nuno', + 'email' => 'enunomaduro@gmail.com', + ]; +}); + +test('pass', function () { + expect($this->user)->toMatchObject([ + 'name' => 'Nuno', + 'email' => 'enunomaduro@gmail.com', + ]); +}); + +test('failures', function () { + expect($this->user)->toMatchObject([ + 'name' => 'Not the same name', + 'email' => 'enunomaduro@gmail.com', + ]); +})->throws(ExpectationFailedException::class); + +test('not failures', function () { + expect($this->user)->not->toMatchObject([ + 'id' => 1, + ]); +})->throws(ExpectationFailedException::class);