What A Pain!

What if you want to check the arguments going in to the last call? Well you can use at():

1

$mock->expects($this->at(7)) // ...

… better hope we never add any other calls!

What if we don’t know the exact parameter that it’s being called with and want to check it with something more complex? Well if you dig really hard in the manual you’ll find there’s a whole bunch of assertions that let you feed in crazier stuff like:

So that’s pretty cool, if you happen to like really obscure features that are impossible to remember.

Surely there’s a better way? Think of the children!

What if you could just ask for all the invocations and test that they were right in that language you’re already using for all your production logic? Wouldn’t that be just dandy!

Turns out you can, but it’s hiding – and I don’t mean it’s hiding in a “you will find this if you read the manual” kind of way, I mean it’s hiding in the source code, where everyone totally looks first for easy examples right?

All you have to do is store the result of $this->any() and you can use it as a spy:

12

$exec->expects($spy = $this->any()) ->method('foo');

(I’ve got to wonder if documenting those extra 7 characters might be the colloquial straw that breaks the PHPUnit manual’s back.)

Now that you have a spy, you can just do normal stuff that calls it, then use normal PHP logic (I had to laugh when I wrote “normal PHP logic”) to confirm it’s right:

123

// get the last invocation$invocation = end($spy->getInvocations());$this->assertEquals('foo', $invocation->arguments[0]);

An Example You Say?

As a concrete example, lets ensure the NSA is spying on its citizens just the right amount.

1234567891011121314151617181920212223242526272829303132333435363738

<?php// What we're testing todayclassAverageCitizen{publicfunctionspyOn(){}}// Our tests (yes, normally these would be in some other file)classTestAverageCitizensextendsPHPUnit_Framework_TestCase{publicfunctiontestSpyingLikeTheNSAShould(){$citizen=$this->getMock('AverageCitizen');$citizen->expects($spy=$this->any())->method('spyOn');$citizen->spyOn("foo");$invocations=$spy->getInvocations();$this->assertEquals(1,count($invocations));// we can easily check specific arguments too$last=end($invocations);$this->assertEquals("foo",$last->parameters[0]);}publicfunctiontestSpyingLikeTheNSADoes(){$citizen=$this->getMock('AverageCitizen');$citizen->expects($spy=$this->any())->method('spyOn');$citizen->spyOn("foo");$citizen->spyOn("bar");$invocations=$spy->getInvocations();$this->assertEquals(1,count($invocations));}}?>

and when we run the tests we can see that even PHPUnit knows the NSA has crossed the line: