The PHPUnit at() matcher, used to determine the order that methods are called on test doubles, has been deprecated. It will be removed in PHPUnit 10. You should refactor your tests to not rely on the order in which methods are invoked. The best replacement depends on how the method was used in the test previously:
-
Order of method calls
Where
at()was used only to enforce the order of calls:$test_processor->expects($this->at(0)) ->method('buildConfigurationForm') ->with($this->anything(), $form_state) ->will($this->returnArgument(0)); $test_processor->expects($this->at(1)) ->method('validateConfigurationForm') ->with($this->anything(), $form_state); $test_processor->expects($this->at(2)) ->method('submitConfigurationForm') ->with($this->anything(), $form_state);We can just replace this with the number of times that the method should be called:
$test_processor->expects($this->once()) ->method('buildConfigurationForm') ->with($this->anything(), $form_state) ->will($this->returnArgument(0)); $test_processor->expects($this->once()) ->method('validateConfigurationForm') ->with($this->anything(), $form_state); $test_processor->expects($this->once()) ->method('submitConfigurationForm') ->with($this->anything(), $form_state); -
Different
with()andwill()used on a single methodWhere different
with()andwill()values were used on a single method, and the test does not strictly care about the order of the calls:$language_manager->expects($this->at(0)) ->method('getLanguage') ->with($this->equalTo($source)) ->will($this->returnValue(new Language(['id' => 'en']))); $language_manager->expects($this->at(2)) ->method('getLanguage') ->with($this->equalTo($source)) ->will($this->returnValue(new Language(['id' => 'en']))); $language_manager->expects($this->at(3)) ->method('getLanguage') ->with($this->equalTo($target)) ->will($this->returnValue(new Language(['id' => 'it'])));We can convert this to
withReturnMap():$language_manager->expects($this->any()) ->method('getLanguage') ->willReturnMap([ [$source, new Language(['id' => $source])], [$target, new Language(['id' => $target])], ]); -
Testing return values only for non-idempotent method calls
Where the order of the calls is important and we only have return values, e.g. we are testing two different sets of expectations in the same method:
$term_storage->expects($this->at(0)) ->method('loadAllParents') ->will($this->returnValue([$term1])); $term_storage->expects($this->at(1)) ->method('loadAllParents') ->will($this->returnValue([$term1, $term2]));We can test for the correct number of calls and use
willReturnOnConsecutiveCalls():$term_storage->expects($this->exactly(2)) ->method('loadAllParents') ->willReturnOnConsecutiveCalls( [$term1], [$term1, $term2], ); -
Testing specific call order with specific parameters
Where the order of calls is important and we have expectations about what is passed:
$this->messenger->expects($this->at(0)) ->method('addError') ->with('no title given'); $this->messenger->expects($this->at(1)) ->method('addError') ->with('element is invisible'); $this->messenger->expects($this->at(2)) ->method('addError') ->with('this missing element is invalid'); $this->messenger->expects($this->at(3)) ->method('addError') ->with('3 errors have been found: <ul-comma-list-mock><li-mock>Test 1</li-mock><li-mock>Test 2 & a half</li-mock><li-mock>Test 3</li-mock></ul-comma-list-mock>');We can test for the correct number of calls and use
withConsecutive():$this->messenger->expects($this->exactly(4)) ->method('addError') ->withConsecutive( ['no title given', FALSE], ['element is invisible', FALSE], ['this missing element is invalid', FALSE], ['3 errors have been found: <ul-comma-list-mock><li-mock>Test 1</li-mock><li-mock>Test 2 & a half</li-mock><li-mock>Test 3</li-mock></ul-comma-list-mock>', FALSE], ); -
Testing specific call order with specific parameter and return values
Where both the passed arguments and return values are important:
$this->connection->expects($this->any()) ->method('query') ->willReturn($statement); $this->connection->expects($this->at(2)) ->method('query') ->with("SELECT 1 FROM pg_constraint WHERE conname = '$expected'") ->willReturn($this->createMock('\Drupal\Core\Database\StatementInterface'));We can combine
withConsecutive()andwillReturnOnConsecutiveCalls():$this->connection->expects($this->exactly(2)) ->method('query') ->withConsecutive( [$this->anything()], ["SELECT 1 FROM pg_constraint WHERE conname = '$expected'"], ) ->willReturnOnConsecutiveCalls( $statement, $this->createMock('\Drupal\Core\Database\StatementInterface'), );
For more information please see the PHPUnit issue where the deprecation was introduced: https://github.com/sebastianbergmann/phpunit/issues/4297