diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index e0f4417f607a..7b90444bddd2 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -329,7 +329,6 @@ private function createABufferedOutputMock() foreach ($this->test->unexpectedOutput as $output => $displayed) { $mock->shouldReceive('doWrite') - ->once() ->ordered() ->with($output, Mockery::any()) ->andReturnUsing(function () use ($output) { diff --git a/tests/Integration/Testing/ArtisanCommandTest.php b/tests/Integration/Testing/ArtisanCommandTest.php new file mode 100644 index 000000000000..82e827732597 --- /dev/null +++ b/tests/Integration/Testing/ArtisanCommandTest.php @@ -0,0 +1,132 @@ +ask('What is your name?'); + + $language = $this->choice('Which language do you prefer?', [ + 'PHP', + 'Ruby', + 'Python', + ]); + + $this->line("Your name is $name and you prefer $language."); + }); + + Artisan::command('slim', function () { + $this->line($this->ask('Who?')); + $this->line($this->ask('What?')); + $this->line($this->ask('Huh?')); + }); + } + + public function test_console_command_that_passes() + { + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'PHP') + ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.') + ->doesntExpectOutput('Your name is Taylor Otwell and you prefer Ruby.') + ->assertExitCode(0); + } + + public function test_console_command_that_passes_with_repeating_output() + { + $this->artisan('slim') + ->expectsQuestion('Who?', 'Taylor') + ->expectsQuestion('What?', 'Taylor') + ->expectsQuestion('Huh?', 'Taylor') + ->expectsOutput('Taylor') + ->doesntExpectOutput('Otwell') + ->expectsOutput('Taylor') + ->expectsOutput('Taylor') + ->assertExitCode(0); + } + + public function test_console_command_that_fails_from_unexpected_output() + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Output "Your name is Taylor Otwell and you prefer PHP." was printed.'); + + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'PHP') + ->doesntExpectOutput('Your name is Taylor Otwell and you prefer PHP.') + ->assertExitCode(0); + } + + public function test_console_command_that_fails_from_missing_output() + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Output "Your name is Taylor Otwell and you prefer PHP." was not printed.'); + + $this->ignoringMockOnceExceptions(function () { + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'Ruby') + ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.') + ->assertExitCode(0); + }); + } + + public function test_console_command_that_fails_from_exit_code_mismatch() + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Expected status code 1 but received 0.'); + + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'PHP') + ->assertExitCode(1); + } + + public function test_console_command_that_fails_from_unordered_output() + { + $this->expectException(InvalidOrderException::class); + + $this->ignoringMockOnceExceptions(function () { + $this->artisan('slim') + ->expectsQuestion('Who?', 'Taylor') + ->expectsQuestion('What?', 'Danger') + ->expectsQuestion('Huh?', 'Otwell') + ->expectsOutput('Taylor') + ->expectsOutput('Otwell') + ->expectsOutput('Danger') + ->assertExitCode(0); + }); + } + + /** + * Don't allow Mockery's InvalidCountException to be reported. Mocks setup + * in PendingCommand cause PHPUnit tearDown() to later throw the exception. + * + * @param callable $callback + * @return void + */ + protected function ignoringMockOnceExceptions(callable $callback) + { + try { + $callback(); + } finally { + try { + Mockery::close(); + } catch (InvalidCountException $e) { + // Ignore mock exception from PendingCommand::expectsOutput(). + } + } + } +}