From af66231382c4170a5e9db0bc42efd9a8e7c8e537 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Sat, 16 Jul 2016 18:21:23 -0400 Subject: [PATCH 01/10] Add tests for custom wasCalled assertions --- tests/AssertionTest.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/AssertionTest.php diff --git a/tests/AssertionTest.php b/tests/AssertionTest.php new file mode 100644 index 0000000..c6d6682 --- /dev/null +++ b/tests/AssertionTest.php @@ -0,0 +1,25 @@ +assertSpyWasCalled( $spy ); + } + + public function test_assert_was_not_called_is_false_when_not_called() { + $spy = \Spies\make_spy(); + $this->assertSpyWasNotCalled( $spy ); + } + + public function test_assert_that_was_called_is_true_when_called() { + $spy = \Spies\make_spy(); + $spy(); + $this->assertThat( $spy, $this->wasCalled() ); + } + + public function test_assert_that_was_called_is_false_when_not_called() { + $spy = \Spies\make_spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalled() ) ); + } +} From 816fef35309a2575e257b2ec7a6adfde5ac480b5 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Sat, 16 Jul 2016 18:21:48 -0400 Subject: [PATCH 02/10] Add wasCalled assertions and \Spies\TestCase --- src/Spies/SpiesConstraintWasCalled.php | 15 +++++++++++++++ src/Spies/TestCase.php | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/Spies/SpiesConstraintWasCalled.php create mode 100644 src/Spies/TestCase.php diff --git a/src/Spies/SpiesConstraintWasCalled.php b/src/Spies/SpiesConstraintWasCalled.php new file mode 100644 index 0000000..d4980c9 --- /dev/null +++ b/src/Spies/SpiesConstraintWasCalled.php @@ -0,0 +1,15 @@ +was_called(); + } + + public function toString() { + return 'was called'; + } +} diff --git a/src/Spies/TestCase.php b/src/Spies/TestCase.php new file mode 100644 index 0000000..c87135b --- /dev/null +++ b/src/Spies/TestCase.php @@ -0,0 +1,16 @@ + Date: Sun, 17 Jul 2016 17:03:15 -0400 Subject: [PATCH 03/10] Add Spy->was_called_with_array --- src/Spies/Spy.php | 54 +++++++++++++++++++++++++++++++++-------------- tests/SpyTest.php | 12 +++++++++++ 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/Spies/Spy.php b/src/Spies/Spy.php index 9944550..ee0af8c 100644 --- a/src/Spies/Spy.php +++ b/src/Spies/Spy.php @@ -18,8 +18,19 @@ public function __construct( $function_name = null ) { $this->function_name = $function_name; } + public function __toString() { + $summary = []; + $i = 0; + $summary[] = empty( $this->call_record ) ? 'never called' : "calls:\n " . implode( ",\n ", array_map( function( $cr ) use ( $i ) { + $i++; + return $i . '. ' . strval( $cr ); + }, $this->call_record ) ) . "\n"; + ( ! empty( $this->function_name ) ) && $summary['function_name'] = $this->function_name; + return '\Spies\Spy(' . implode( $summary ) . ')'; + } + /** - * Allows Spy to be called as a function + * Allows Spy to be called as a function * * Alias for `call` */ @@ -70,7 +81,7 @@ public static function passed_arg( $index ) { } /** - * Return the function name + * Return the function name * * @return string The function name */ @@ -78,7 +89,7 @@ public function get_function_name() { if ( isset( $this->function_name ) ) { return $this->function_name; } - return 'anonymous function'; + return 'a spy'; } public function set_function_name( $function_name ) { @@ -101,7 +112,7 @@ public function call() { } /** - * Call this mocked function with an array of arguments. + * Call this mocked function with an array of arguments. * * Same as `call`, but with an array of arguments instead of any number. * @@ -114,7 +125,7 @@ public function call_with_array( $args ) { } /** - * Clear the record of calls for this spy + * Clear the record of calls for this spy */ public function clear_call_record() { $this->call_record = []; @@ -198,7 +209,7 @@ public function that_returns( $value ) { * mock_function( 'add_one' )->and_return( function( $a ) { * return $a + 1; * } ); - * + * * @param mixed $value The value to return when this spy is called * @return Spy This Spy */ @@ -219,7 +230,7 @@ public function and_return( $value ) { * particular value if certain arguments are present when the function is * called. * - * @param mixed $arg... The arguments to use when defining a behavior + * @param mixed $arg... The arguments to use when defining a behavior * @return Spy This spy */ public function with() { @@ -237,7 +248,7 @@ public function get_times_called() { } /** - * Return the call record for a single call + * Return the call record for a single call * * @param integer $index The 0-based index of the call record to return * @return array|null The call record @@ -247,7 +258,7 @@ public function get_call( $index ) { } /** - * Return true if the spy was called + * Return true if the spy was called * * @return boolean True if the spy was called */ @@ -256,7 +267,7 @@ public function was_called() { } /** - * Return true if the spy was called a certain number of times + * Return true if the spy was called a certain number of times * * @param integer $times The number of times the function should have been called * @return boolean True if the spy was called $times times @@ -266,13 +277,14 @@ public function was_called_times( $times ) { } /** - * Return true if the spy was called with a certain number of arguments + * Return true if the spy was called with a certain number of arguments * - * @param mixed $arg... The arguments to look for in the call record + * Array version of was_called_with + * + * @param array $arg The arguments to look for in the call record * @return boolean True if the spy was called with the arguments */ - public function was_called_with() { - $args = func_get_args(); + public function was_called_with_array( $args ) { $matching_calls = array_filter( $this->get_called_functions(), function( $call ) use ( $args ) { return ( Helpers::do_args_match( $call->get_args(), $args ) ); } ); @@ -280,7 +292,7 @@ public function was_called_with() { } /** - * Return true if a spy call causes a function to return true + * Return true if a spy call causes a function to return true * * @param callable $callable A function to call with every set of arguments * @return boolean True if the callable function matches at least one set of arguments @@ -292,6 +304,16 @@ public function was_called_when( $callable ) { return ( count( $matching_calls ) > 0 ); } + /** + * Return true if the spy was called with a certain number of arguments + * + * @param mixed $arg... The arguments to look for in the call record + * @return boolean True if the spy was called with the arguments + */ + public function was_called_with() { + return $this->was_called_with_array( func_get_args() ); + } + public function was_called_before( $spy ) { $call_record = $this->get_called_functions(); if ( count( $call_record ) < 1 ) { @@ -311,7 +333,7 @@ private function set_arguments( $args ) { } /** - * Add a function call to the call record + * Add a function call to the call record * * You should not need to call this directly. */ diff --git a/tests/SpyTest.php b/tests/SpyTest.php index 6caea86..86d200b 100644 --- a/tests/SpyTest.php +++ b/tests/SpyTest.php @@ -86,6 +86,18 @@ public function test_spy_was_called_times_returns_false_if_the_argument_does_not $this->assertFalse( $spy->was_called_times( 6 ) ); } + public function test_spy_was_called_with_array_returns_true_if_the_spy_was_called_with_the_arguments_provided() { + $spy = \Spies\make_spy(); + $spy( 'foo', 'bar', 'baz' ); + $this->assertTrue( $spy->was_called_with_array( [ 'foo', 'bar', 'baz' ] ) ); + } + + public function test_spy_was_called_with_array_returns_false_if_the_spy_was_not_called_with_the_arguments_provided() { + $spy = \Spies\make_spy(); + $spy( 'foo' ); + $this->assertFalse( $spy->was_called_with( [ 'foo', 'bar', 'baz' ] ) ); + } + public function test_spy_was_called_with_returns_true_if_the_spy_was_called_with_the_arguments_provided() { $spy = \Spies\make_spy(); $spy( 'foo', 'bar', 'baz' ); From 7d0151f7f8d8e6be6638e74e1b2b206630f135c1 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Sun, 17 Jul 2016 17:03:50 -0400 Subject: [PATCH 04/10] Add assertSpyWasCalledWith --- src/Spies/ArgumentFormatter.php | 21 +++++++++++++ src/Spies/FailureGenerator.php | 36 ++++++++++++++++++++++ src/Spies/SpiesConstraintWasCalled.php | 14 ++++++++- src/Spies/SpiesConstraintWasCalledWith.php | 35 +++++++++++++++++++++ src/Spies/SpiesConstraintWasNotCalled.php | 22 +++++++++++++ src/Spies/SpyCall.php | 4 +++ src/Spies/SpyCallFormatter.php | 18 +++++++++++ src/Spies/TestCase.php | 15 ++++++++- tests/AssertionTest.php | 27 ++++++++++++++-- 9 files changed, 188 insertions(+), 4 deletions(-) create mode 100644 src/Spies/ArgumentFormatter.php create mode 100644 src/Spies/FailureGenerator.php create mode 100644 src/Spies/SpiesConstraintWasCalledWith.php create mode 100644 src/Spies/SpiesConstraintWasNotCalled.php create mode 100644 src/Spies/SpyCallFormatter.php diff --git a/src/Spies/ArgumentFormatter.php b/src/Spies/ArgumentFormatter.php new file mode 100644 index 0000000..591b093 --- /dev/null +++ b/src/Spies/ArgumentFormatter.php @@ -0,0 +1,21 @@ +args = $args; + } + + public function __toString() { + if ( empty( $this->args ) ) { + return 'no arguments'; + } + return 'arguments: ( ' . $this->get_args_as_array() . ' )'; + } + + private function get_args_as_array() { + return implode( ', ', array_map( 'json_encode', $this->args ) ); + } +} diff --git a/src/Spies/FailureGenerator.php b/src/Spies/FailureGenerator.php new file mode 100644 index 0000000..07f1256 --- /dev/null +++ b/src/Spies/FailureGenerator.php @@ -0,0 +1,36 @@ +add_message( $spy->get_function_name() . ' is called' ); + } + + public function spy_was_called( $spy ) { + $this->add_message( $spy->get_function_name() . ' is not called' ); + } + + public function spy_was_not_called_with( $spy, $args ) { + $this->spy_was_not_called( $spy ); + $desc = 'with '; + $desc .= strval( new ArgumentFormatter( $args ) ); + $this->add_message( $desc ); + } + + public function spy_was_not_called_with_additional( $spy ) { + $desc = $spy->get_function_name() . ' was actually '; + $calls = $spy->get_called_functions(); + $desc .= empty( $calls ) ? 'not called at all' : 'called with:' . strval( new SpyCallFormatter( $calls ) ); + $this->add_message( $desc ); + } + + public function add_message( $message ) { + $this->messages[] = $message; + } + + public function get_message() { + return implode( ' ', $this->messages ); + } +} diff --git a/src/Spies/SpiesConstraintWasCalled.php b/src/Spies/SpiesConstraintWasCalled.php index d4980c9..a27411f 100644 --- a/src/Spies/SpiesConstraintWasCalled.php +++ b/src/Spies/SpiesConstraintWasCalled.php @@ -9,7 +9,19 @@ public function matches( $other ) { return $other->was_called(); } + public function failureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called( $other ); + return $generator->get_message(); + } + + protected function additionalFailureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_with_additional( $other ); + return $generator->get_message(); + } + public function toString() { - return 'was called'; + return ''; } } diff --git a/src/Spies/SpiesConstraintWasCalledWith.php b/src/Spies/SpiesConstraintWasCalledWith.php new file mode 100644 index 0000000..ff4875b --- /dev/null +++ b/src/Spies/SpiesConstraintWasCalledWith.php @@ -0,0 +1,35 @@ +expected_args = $args; + } + + public function matches( $other ) { + if ( ! $other instanceof \Spies\Spy ) { + return false; + } + return $other->was_called_with_array( $this->expected_args ); + } + + protected function failureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_with( $other, $this->expected_args ); + return $generator->get_message(); + } + + protected function additionalFailureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_with_additional( $other ); + return $generator->get_message(); + } + + public function toString() { + return ''; + } +} + diff --git a/src/Spies/SpiesConstraintWasNotCalled.php b/src/Spies/SpiesConstraintWasNotCalled.php new file mode 100644 index 0000000..0dfb419 --- /dev/null +++ b/src/Spies/SpiesConstraintWasNotCalled.php @@ -0,0 +1,22 @@ +was_called(); + } + + public function failureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_called( $other ); + return $generator->get_message(); + } + + public function toString() { + return ''; + } +} + diff --git a/src/Spies/SpyCall.php b/src/Spies/SpyCall.php index c790db4..246d629 100644 --- a/src/Spies/SpyCall.php +++ b/src/Spies/SpyCall.php @@ -27,4 +27,8 @@ public function get_args() { public function get_timestamp() { return $this->timestamp; } + + public function __toString() { + return strval( new ArgumentFormatter( $this->get_args() ) ); + } } diff --git a/src/Spies/SpyCallFormatter.php b/src/Spies/SpyCallFormatter.php new file mode 100644 index 0000000..c9d9da9 --- /dev/null +++ b/src/Spies/SpyCallFormatter.php @@ -0,0 +1,18 @@ +calls = $calls; + } + + public function __toString() { + $i = 0; + return "\n " . implode( ",\n ", array_map( function( $call ) use ( &$i ) { + $i++; + return $i . '. ' . strval( $call ); + }, $this->calls ) ) . "\n"; + } +} diff --git a/src/Spies/TestCase.php b/src/Spies/TestCase.php index c87135b..77db11c 100644 --- a/src/Spies/TestCase.php +++ b/src/Spies/TestCase.php @@ -7,10 +7,23 @@ public static function assertSpyWasCalled( $condition, $message = '' ) { } public static function assertSpyWasNotCalled( $condition, $message = '' ) { - self::assertThat( $condition, self::logicalNot( self::wasCalled() ), $message ); + self::assertThat( $condition, self::wasNotCalled(), $message ); } public static function wasCalled() { return new \Spies\SpiesConstraintWasCalled; } + + public static function wasNotCalled() { + return new \Spies\SpiesConstraintWasNotCalled; + } + + public static function wasCalledWith( $args ) { + return new \Spies\SpiesConstraintWasCalledWith( $args ); + } + + public static function assertSpyWasCalledWith( $condition, $args, $message = '' ) { + self::assertThat( $condition, self::wasCalledWith( $args ), $message ); + } + } diff --git a/tests/AssertionTest.php b/tests/AssertionTest.php index c6d6682..3266106 100644 --- a/tests/AssertionTest.php +++ b/tests/AssertionTest.php @@ -7,7 +7,7 @@ public function test_assert_was_called_is_true_when_called() { $this->assertSpyWasCalled( $spy ); } - public function test_assert_was_not_called_is_false_when_not_called() { + public function test_assert_was_not_called_is_true_when_not_called() { $spy = \Spies\make_spy(); $this->assertSpyWasNotCalled( $spy ); } @@ -18,8 +18,31 @@ public function test_assert_that_was_called_is_true_when_called() { $this->assertThat( $spy, $this->wasCalled() ); } - public function test_assert_that_was_called_is_false_when_not_called() { + public function test_assert_that_was_called_is_true_when_not_called() { + $spy = \Spies\make_spy(); + $this->assertThat( $spy, $this->wasNotCalled() ); + } + + public function test_assert_that_logical_not_was_called_is_true_when_not_called() { $spy = \Spies\make_spy(); $this->assertThat( $spy, $this->logicalNot( $this->wasCalled() ) ); } + + public function test_assert_that_was_called_with_is_true_when_called_with_args() { + $spy = \Spies\make_spy(); + $spy( 'a', 'b', 'c' ); + $this->assertThat( $spy, $this->wasCalledWith( [ 'a', 'b', 'c' ] ) ); + } + + public function test_assert_that_was_logical_not_called_with_is_true_when_not_called_with_args() { + $spy = \Spies\make_spy(); + $spy( 'b', 'b', 'c' ); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledWith( [ 'a', 'b', 'c' ] ) ) ); + } + + public function test_assert_spy_was_called_with_is_true_when_called_with_args() { + $spy = \Spies\make_spy(); + $spy( 'a', 'b', 'c' ); + $this->assertSpyWasCalledWith( $spy, [ 'a', 'b', 'c' ] ); + } } From 63386eedd50d2e14a386460dcc75df1dc26a5d83 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 19 Jul 2016 17:43:32 -0400 Subject: [PATCH 05/10] Add wasCalledTimes assertions --- src/Spies/FailureGenerator.php | 19 +++++++--- src/Spies/SpiesConstraintWasCalledTimes.php | 35 ++++++++++++++++++ src/Spies/TestCase.php | 27 ++++++++++---- tests/AssertionTest.php | 41 +++++++++++++++++++++ 4 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 src/Spies/SpiesConstraintWasCalledTimes.php diff --git a/src/Spies/FailureGenerator.php b/src/Spies/FailureGenerator.php index 07f1256..998e82f 100644 --- a/src/Spies/FailureGenerator.php +++ b/src/Spies/FailureGenerator.php @@ -4,6 +4,14 @@ class FailureGenerator { private $messages = []; + public function add_message( $message ) { + $this->messages[] = $message; + } + + public function get_message() { + return implode( ' ', $this->messages ); + } + public function spy_was_not_called( $spy ) { $this->add_message( $spy->get_function_name() . ' is called' ); } @@ -26,11 +34,10 @@ public function spy_was_not_called_with_additional( $spy ) { $this->add_message( $desc ); } - public function add_message( $message ) { - $this->messages[] = $message; - } - - public function get_message() { - return implode( ' ', $this->messages ); + public function spy_was_not_called_times( $spy, $count ) { + $this->spy_was_not_called( $spy ); + $desc = $count . ' '; + $desc .= $count === 1 ? 'time' : 'times'; + $this->add_message( $desc ); } } diff --git a/src/Spies/SpiesConstraintWasCalledTimes.php b/src/Spies/SpiesConstraintWasCalledTimes.php new file mode 100644 index 0000000..46e03a9 --- /dev/null +++ b/src/Spies/SpiesConstraintWasCalledTimes.php @@ -0,0 +1,35 @@ +count = $count; + } + + public function matches( $other ) { + if ( ! $other instanceof \Spies\Spy ) { + return false; + } + return $other->was_called_times( $this->count ); + } + + public function failureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_times( $other, $this->count ); + return $generator->get_message(); + } + + protected function additionalFailureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_with_additional( $other ); + return $generator->get_message(); + } + + public function toString() { + return ''; + } +} + diff --git a/src/Spies/TestCase.php b/src/Spies/TestCase.php index 77db11c..7ab1673 100644 --- a/src/Spies/TestCase.php +++ b/src/Spies/TestCase.php @@ -2,13 +2,6 @@ namespace Spies; abstract class TestCase extends \PHPUnit_Framework_TestCase { - public static function assertSpyWasCalled( $condition, $message = '' ) { - self::assertThat( $condition, self::wasCalled(), $message ); - } - - public static function assertSpyWasNotCalled( $condition, $message = '' ) { - self::assertThat( $condition, self::wasNotCalled(), $message ); - } public static function wasCalled() { return new \Spies\SpiesConstraintWasCalled; @@ -22,8 +15,28 @@ public static function wasCalledWith( $args ) { return new \Spies\SpiesConstraintWasCalledWith( $args ); } + public static function wasCalledTimes( $count ) { + return new \Spies\SpiesConstraintWasCalledTimes( $count ); + } + + public static function assertSpyWasCalled( $condition, $message = '' ) { + self::assertThat( $condition, self::wasCalled(), $message ); + } + + public static function assertSpyWasNotCalled( $condition, $message = '' ) { + self::assertThat( $condition, self::wasNotCalled(), $message ); + } + public static function assertSpyWasCalledWith( $condition, $args, $message = '' ) { self::assertThat( $condition, self::wasCalledWith( $args ), $message ); } + public static function assertSpyWasCalledTimes( $condition, $count, $message = '' ) { + self::assertThat( $condition, self::wasCalledTimes( $count ), $message ); + } + + public static function assertSpyWasNotCalledTimes( $condition, $count, $message = '' ) { + self::assertThat( $condition, self::logicalNot( self::wasCalledTimes( $count ) ), $message ); + } + } diff --git a/tests/AssertionTest.php b/tests/AssertionTest.php index 3266106..4861e73 100644 --- a/tests/AssertionTest.php +++ b/tests/AssertionTest.php @@ -45,4 +45,45 @@ public function test_assert_spy_was_called_with_is_true_when_called_with_args() $spy( 'a', 'b', 'c' ); $this->assertSpyWasCalledWith( $spy, [ 'a', 'b', 'c' ] ); } + + public function test_assert_was_called_times_is_true_when_called_once() { + $spy = \Spies\make_spy(); + $spy(); + $this->assertThat( $spy, $this->wasCalledTimes( 1 ) ); + } + + public function test_assert_was_called_times_is_true_when_called_twice() { + $spy = \Spies\make_spy(); + $spy(); + $spy(); + $this->assertThat( $spy, $this->wasCalledTimes( 2 ) ); + } + + public function test_assert_was_called_times_is_false_when_called_less_than_number() { + $spy = \Spies\make_spy(); + $spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledTimes( 2 ) ) ); + } + + public function test_assert_was_called_times_is_false_when_called_more_than_number() { + $spy = \Spies\make_spy(); + $spy(); + $spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledTimes( 1 ) ) ); + } + + public function test_assert_spy_was_called_times_is_true_when_called_that_number() { + $spy = \Spies\make_spy(); + $spy(); + $spy(); + $spy(); + $this->assertSpyWasCalledTimes( $spy, 3 ); + } + + public function test_assert_spy_was_not_called_times_is_true_when_not_called_that_number() { + $spy = \Spies\make_spy(); + $spy(); + $this->assertSpyWasNotCalledTimes( $spy, 3 ); + } + } From 11555974801acd2a52007d51aa44d5120396432e Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 19 Jul 2016 17:59:29 -0400 Subject: [PATCH 06/10] Add wasCalledBefore constraint --- src/Spies/FailureGenerator.php | 6 +++ src/Spies/SpiesConstraintWasCalledBefore.php | 30 +++++++++++++ src/Spies/TestCase.php | 12 +++++ tests/AssertionTest.php | 46 ++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 src/Spies/SpiesConstraintWasCalledBefore.php diff --git a/src/Spies/FailureGenerator.php b/src/Spies/FailureGenerator.php index 998e82f..4d1be31 100644 --- a/src/Spies/FailureGenerator.php +++ b/src/Spies/FailureGenerator.php @@ -40,4 +40,10 @@ public function spy_was_not_called_times( $spy, $count ) { $desc .= $count === 1 ? 'time' : 'times'; $this->add_message( $desc ); } + + public function spy_was_not_called_before( $spy, $target_spy ) { + $this->spy_was_not_called( $spy ); + $desc = 'before ' . $target_spy->get_function_name(); + $this->add_message( $desc ); + } } diff --git a/src/Spies/SpiesConstraintWasCalledBefore.php b/src/Spies/SpiesConstraintWasCalledBefore.php new file mode 100644 index 0000000..0e0c895 --- /dev/null +++ b/src/Spies/SpiesConstraintWasCalledBefore.php @@ -0,0 +1,30 @@ +target_spy = $target_spy; + } + + public function matches( $other ) { + if ( ! $other instanceof \Spies\Spy ) { + return false; + } + return $other->was_called_before( $this->target_spy ); + } + + public function failureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_before( $other, $this->target_spy ); + return $generator->get_message(); + } + + public function toString() { + return ''; + } +} + + diff --git a/src/Spies/TestCase.php b/src/Spies/TestCase.php index 7ab1673..1a9f23b 100644 --- a/src/Spies/TestCase.php +++ b/src/Spies/TestCase.php @@ -19,6 +19,10 @@ public static function wasCalledTimes( $count ) { return new \Spies\SpiesConstraintWasCalledTimes( $count ); } + public static function wasCalledBefore( $spy ) { + return new \Spies\SpiesConstraintWasCalledBefore( $spy ); + } + public static function assertSpyWasCalled( $condition, $message = '' ) { self::assertThat( $condition, self::wasCalled(), $message ); } @@ -39,4 +43,12 @@ public static function assertSpyWasNotCalledTimes( $condition, $count, $message self::assertThat( $condition, self::logicalNot( self::wasCalledTimes( $count ) ), $message ); } + public static function assertSpyWasCalledBefore( $condition, $target_spy, $message = '' ) { + self::assertThat( $condition, self::wasCalledBefore( $target_spy ), $message ); + } + + public static function assertSpyWasNotCalledBefore( $condition, $target_spy, $message = '' ) { + self::assertThat( $condition, self::logicalNot( self::wasCalledBefore( $target_spy ) ), $message ); + } + } diff --git a/tests/AssertionTest.php b/tests/AssertionTest.php index 4861e73..b48b9ee 100644 --- a/tests/AssertionTest.php +++ b/tests/AssertionTest.php @@ -86,4 +86,50 @@ public function test_assert_spy_was_not_called_times_is_true_when_not_called_tha $this->assertSpyWasNotCalledTimes( $spy, 3 ); } + public function test_assert_that_spy_was_called_before_is_true_when_called_before_other_spy() { + $spy = \Spies\make_spy(); + $spy2 = \Spies\make_spy(); + $spy(); + $spy2(); + $this->assertThat( $spy, $this->wasCalledBefore( $spy2 ) ); + } + + public function test_assert_that_spy_was_called_before_is_false_when_called_after_other_spy() { + $spy = \Spies\make_spy(); + $spy2 = \Spies\make_spy(); + $spy2(); + $spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledBefore( $spy2 ) ) ); + } + + public function test_assert_that_spy_was_called_before_is_false_when_other_spy_not_called() { + $spy = \Spies\make_spy(); + $spy2 = \Spies\make_spy(); + $spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledBefore( $spy2 ) ) ); + } + + public function test_assert_that_spy_was_called_before_is_false_when_spy_not_called() { + $spy = \Spies\make_spy(); + $spy2 = \Spies\make_spy(); + $spy2(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledBefore( $spy2 ) ) ); + } + + public function test_assert_spy_was_called_before_is_true_when_called_before_other_spy() { + $spy = \Spies\make_spy(); + $spy2 = \Spies\make_spy(); + $spy(); + $spy2(); + $this->assertSpyWasCalledBefore( $spy, $spy2 ); + } + + public function test_assert_spy_was_not_called_before_is_true_when_called_after_other_spy() { + $spy = \Spies\make_spy(); + $spy2 = \Spies\make_spy(); + $spy2(); + $spy(); + $this->assertSpyWasNotCalledBefore( $spy, $spy2 ); + } + } From 17d3949ced014960c8be6c59f664af29161829ca Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 26 Jul 2016 23:21:16 -0400 Subject: [PATCH 07/10] Add wasCalledWhen Constraint --- src/Spies/FailureGenerator.php | 7 +++ src/Spies/SpiesConstraintWasCalledWhen.php | 35 +++++++++++++ src/Spies/TestCase.php | 12 +++++ tests/AssertionTest.php | 60 ++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 src/Spies/SpiesConstraintWasCalledWhen.php diff --git a/src/Spies/FailureGenerator.php b/src/Spies/FailureGenerator.php index 4d1be31..bec1fc1 100644 --- a/src/Spies/FailureGenerator.php +++ b/src/Spies/FailureGenerator.php @@ -46,4 +46,11 @@ public function spy_was_not_called_before( $spy, $target_spy ) { $desc = 'before ' . $target_spy->get_function_name(); $this->add_message( $desc ); } + + public function spy_was_not_called_when( $spy ) { + $this->spy_was_not_called( $spy ); + $desc = 'with arguments matching the provided function'; + $this->add_message( $desc ); + } + } diff --git a/src/Spies/SpiesConstraintWasCalledWhen.php b/src/Spies/SpiesConstraintWasCalledWhen.php new file mode 100644 index 0000000..2cc443c --- /dev/null +++ b/src/Spies/SpiesConstraintWasCalledWhen.php @@ -0,0 +1,35 @@ +expected_callable = $callable; + } + + public function matches( $other ) { + if ( ! $other instanceof \Spies\Spy ) { + return false; + } + return $other->was_called_when( $this->expected_callable ); + } + + protected function failureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_when( $other ); + return $generator->get_message(); + } + + protected function additionalFailureDescription( $other ) { + $generator = new FailureGenerator(); + $generator->spy_was_not_called_with_additional( $other ); + return $generator->get_message(); + } + + public function toString() { + return ''; + } +} + diff --git a/src/Spies/TestCase.php b/src/Spies/TestCase.php index 1a9f23b..52301e2 100644 --- a/src/Spies/TestCase.php +++ b/src/Spies/TestCase.php @@ -23,6 +23,10 @@ public static function wasCalledBefore( $spy ) { return new \Spies\SpiesConstraintWasCalledBefore( $spy ); } + public static function wasCalledWhen( $callable ) { + return new \Spies\SpiesConstraintWasCalledWhen( $callable ); + } + public static function assertSpyWasCalled( $condition, $message = '' ) { self::assertThat( $condition, self::wasCalled(), $message ); } @@ -51,4 +55,12 @@ public static function assertSpyWasNotCalledBefore( $condition, $target_spy, $me self::assertThat( $condition, self::logicalNot( self::wasCalledBefore( $target_spy ) ), $message ); } + public static function assertSpyWasCalledWhen( $condition, $callable, $message = '' ) { + self::assertThat( $condition, self::wasCalledWhen( $callable ), $message ); + } + + public static function assertSpyWasNotCalledWhen( $condition, $callable, $message = '' ) { + self::assertThat( $condition, self::logicalNot( self::wasCalledWhen( $callable ) ), $message ); + } + } diff --git a/tests/AssertionTest.php b/tests/AssertionTest.php index b48b9ee..fb274b4 100644 --- a/tests/AssertionTest.php +++ b/tests/AssertionTest.php @@ -132,4 +132,64 @@ public function test_assert_spy_was_not_called_before_is_true_when_called_after_ $this->assertSpyWasNotCalledBefore( $spy, $spy2 ); } + public function test_assert_that_spy_was_called_when_is_true_when_called_function_returns_true() { + $spy = \Spies\make_spy(); + $spy(); + $this->assertThat( $spy, $this->wasCalledWhen( function() { + return true; + } ) ); + } + + public function test_assert_that_spy_was_called_when_is_false_when_called_function_returns_false() { + $spy = \Spies\make_spy(); + $spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledWhen( function() { + return false; + } ) ) ); + } + + public function test_assert_that_spy_was_called_when_is_false_when_spy_was_not_called() { + $spy = \Spies\make_spy(); + $this->assertThat( $spy, $this->logicalNot( $this->wasCalledWhen( function() { + return true; + } ) ) ); + } + + public function test_assert_that_spy_was_called_when_function_is_called_with_spy_args() { + $spy = \Spies\make_spy(); + $spy( 'hello', 'world' ); + $this->assertThat( $spy, $this->wasCalledWhen( function( $args ) { + return ( $args === [ 'hello', 'world' ] ); + } ) ); + } + + public function test_assert_that_spy_was_called_when_function_is_called_for_each_call() { + $spy = \Spies\make_spy(); + $spy( 1 ); + $spy( 2 ); + $count = 0; + $this->assertThat( $spy, $this->wasCalledWhen( function() use ( &$count ) { + $count ++; + return true; + } ) ); + $this->assertEquals( 2, $count ); + } + + public function test_assert_spy_was_called_when_is_true_when_called_function_returns_true() { + $spy = \Spies\make_spy(); + $spy( 'hi' ); + $spy( 'yo' ); + $this->assertSpyWasCalledWhen( $spy, function( $args ) { + return ( $args === [ 'yo' ] ); + } ); + } + + public function test_assert_spy_was_called_when_is_false_when_called_function_returns_false() { + $spy = \Spies\make_spy(); + $spy(); + $spy( 'yo' ); + $this->assertSpyWasNotCalledWhen( $spy, function( $args ) { + return ( $args === [ 'hi' ] ); + } ); + } } From cb33f15dceeb676a1e9807d7cc115618a25e9d2a Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 26 Jul 2016 23:38:18 -0400 Subject: [PATCH 08/10] Update README with summary of custom assertions --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index d00c756..124cd57 100644 --- a/README.md +++ b/README.md @@ -316,3 +316,27 @@ function test_calculation() { add_together( 2, 3 ); } ``` + +## PHPUnit Custom Assertions + +If you prefer to use PHPUnit custom assertions rather than Expectations, those are also available (although you must base your test class on `\Spies\TestCase`): + +```php +class MyTest extends \Spies\TestCase { + function test_spy_is_called_correctly() { + $spy = \Spies\make_spy(); + $spy( 'hello', 'world', 7 ); + $spy( 'hello', 'world', 8 ); + $this->assertSpyWasCalledWith( 'hello', 'world', \Spies\any() ); + } +} +``` + +Custom assertions will provide detailed information about why your test failed, which is much better than "false is not true". + +``` +Failed asserting that a spy is called with arguments: ( "a", "b", "c" ). +a spy was actually called with: + 1. arguments: ( "b", "b", "c" ), + 2. arguments: ( "m", "b", "c" ) +``` From 34a551b488adc9e6129ec0f949b86fd2312ce206 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 26 Jul 2016 23:48:24 -0400 Subject: [PATCH 09/10] Add Constraints to API doc --- API.md | 24 ++++++++++++++++++++++++ README.md | 2 ++ 2 files changed, 26 insertions(+) diff --git a/API.md b/API.md index 952c1df..5067d9b 100644 --- a/API.md +++ b/API.md @@ -91,3 +91,27 @@ - `once()`: Alias for `times( 1 )`. - `twice()`: Alias for `times( 2 )`. - `before( $spy )`: Add an expected behavior that the spy was called before $spy. + +# PHPUnit Custom Assertions + +These are methods available on instances of `\Spies\TestCase`. + +### Constraints for `assertThat()` + +- `wasCalled()` +- `wasNotCalled()` +- `wasCalledTimes( $count )` +- `wasCalledBefore( $spy )` +- `wasCalledWhen( $callable )` + +### Assertions + +- `assertSpyWasCalled( $spy )` +- `assertSpyWasNotCalled( $spy )` +- `assertSpyWasCalledWith( $spy, $args )` +- `assertSpyWasCalledTimes( $spy, $count )` +- `assertSpyWasNotCalledTimes( $spy, $count )` +- `assertSpyWasCalledBefore( $spy, $other_spy )` +- `assertSpyWasNotCalledBefore( $spy, $other_spy )` +- `assertSpyWasCalledWhen( $spy, $callable )` +- `assertSpyWasNotCalledWhen( $spy, $callable )` diff --git a/README.md b/README.md index 124cd57..827712c 100644 --- a/README.md +++ b/README.md @@ -340,3 +340,5 @@ a spy was actually called with: 1. arguments: ( "b", "b", "c" ), 2. arguments: ( "m", "b", "c" ) ``` + +See the [API document](API.md) for the full list of custom assertions available. From 5861c4469ea93368a17bc610da70b91f7274a19b Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 26 Jul 2016 23:50:47 -0400 Subject: [PATCH 10/10] Add assertSpyWasNotCalledWith assertion --- API.md | 1 + src/Spies/TestCase.php | 4 ++++ tests/AssertionTest.php | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/API.md b/API.md index 5067d9b..e6579fd 100644 --- a/API.md +++ b/API.md @@ -109,6 +109,7 @@ These are methods available on instances of `\Spies\TestCase`. - `assertSpyWasCalled( $spy )` - `assertSpyWasNotCalled( $spy )` - `assertSpyWasCalledWith( $spy, $args )` +- `assertSpyWasNotCalledWith( $spy, $args )` - `assertSpyWasCalledTimes( $spy, $count )` - `assertSpyWasNotCalledTimes( $spy, $count )` - `assertSpyWasCalledBefore( $spy, $other_spy )` diff --git a/src/Spies/TestCase.php b/src/Spies/TestCase.php index 52301e2..cd9fc8c 100644 --- a/src/Spies/TestCase.php +++ b/src/Spies/TestCase.php @@ -35,6 +35,10 @@ public static function assertSpyWasNotCalled( $condition, $message = '' ) { self::assertThat( $condition, self::wasNotCalled(), $message ); } + public static function assertSpyWasNotCalledWith( $condition, $args, $message = '' ) { + self::assertThat( $condition, self::logicalNot( self::wasCalledWith( $args ) ), $message ); + } + public static function assertSpyWasCalledWith( $condition, $args, $message = '' ) { self::assertThat( $condition, self::wasCalledWith( $args ), $message ); } diff --git a/tests/AssertionTest.php b/tests/AssertionTest.php index fb274b4..dcde8d4 100644 --- a/tests/AssertionTest.php +++ b/tests/AssertionTest.php @@ -46,6 +46,12 @@ public function test_assert_spy_was_called_with_is_true_when_called_with_args() $this->assertSpyWasCalledWith( $spy, [ 'a', 'b', 'c' ] ); } + public function test_assert_spy_was_not_called_with_is_true_when_not_called_with_args() { + $spy = \Spies\make_spy(); + $spy( 'e', 'b', 'c' ); + $this->assertSpyWasNotCalledWith( $spy, [ 'a', 'b', 'c' ] ); + } + public function test_assert_was_called_times_is_true_when_called_once() { $spy = \Spies\make_spy(); $spy();