Only this, and nothing more
So I am writing a PHPUnit mock object, added ensure calls and I wanted to also ensure that no more method calls happens than the ones I ensured. This is done by the following snippet (the actual code does more with the expects call of course):
<span style="color: #000000"><span style="color: #0000BB"><?php<br>$schema </span><span style="color: #007700">= </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">getMockBuilder</span><span style="color: #007700">(</span><span style="color: #DD0000">'Drupal\Core\Database\Schema'</span><span style="color: #007700">)<br> -></span><span style="color: #0000BB">disableOriginalConstructor</span><span style="color: #007700">()<br> -></span><span style="color: #0000BB">getMock</span><span style="color: #007700">();<br></span><span style="color: #0000BB">$schema</span><span style="color: #007700">-></span><span style="color: #0000BB">expects</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">at</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: #007700">))<br> -></span><span style="color: #0000BB">method</span><span style="color: #007700">(</span><span style="color: #DD0000">'tableExists'</span><span style="color: #007700">);<br></span><span style="color: #0000BB">$schema</span><span style="color: #007700">-></span><span style="color: #0000BB">expects</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">at</span><span style="color: #007700">(</span><span style="color: #0000BB">1</span><span style="color: #007700">))<br> -></span><span style="color: #0000BB">method</span><span style="color: #007700">(</span><span style="color: #DD0000">'createTable'</span><span style="color: #007700">);<br></span><span style="color: #0000BB">$schema</span><span style="color: #007700">-></span><span style="color: #0000BB">expects</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">at</span><span style="color: #007700">(</span><span style="color: #0000BB">2</span><span style="color: #007700">))<br> -></span><span style="color: #0000BB">method</span><span style="color: #007700">(</span><span style="color: #DD0000">'createTable'</span><span style="color: #007700">);<br></span><span style="color: #0000BB">$schema</span><span style="color: #007700">-></span><span style="color: #0000BB">expects</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">exactly</span><span style="color: #007700">(</span><span style="color: #0000BB">3</span><span style="color: #007700">))<br> -></span><span style="color: #0000BB">method</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">anything</span><span style="color: #007700">());<br></span><span style="color: #0000BB">?></span></span>
There are two things of note here: One, the method()
call accepts not just the typical strings but also constraints which are not the same as the matchers passed to expects()
.
Two, expectations can overlap. PHPunit will happily fire every expectation, even if there is more than one set for the same method. If method()
would only accept simple strings then it'd be tempting to collect expectations by method name (or presume PHPunit works that way) but simply this is not happening because, as above, method()
accepts more than strings. Instead, when a method call happens, PHPUnit fires each expectation and each decide whether it's a match by using the the matcher passed to expects
and the constraint to method
and nothing else. So even if we add a with()
call, it is not used to determine matching only to verify the expected behavior and this is why it is not possible to simply mock multiple calls to the same method with different arguments.