Code to be tested:
// Add the activation provider argument to the factory definition
$factoryDefinition = $container->getDefinition('gremo_subscription_factory');
$factoryDefinition->addArgument(new Reference($providerId));
Test method should check the addArgument method, including $providerId argument. I'm just learining PHPUnit and right now I'm only able to call $this->anything():
$container->expects($this->at(3))
->method('getDefinition')
->with('gremo_subscription_factory')
->will($this->returnValue($factory));
$factory->expects($this->once())
->method('addArgument')
->with($this->anything());
$this->pass->process($container);
How can I check that argument type is Reference class, and (in turn) its argument is exactly the string $providerId?
This is pretty complicated, especially since the Reference class is not dependency injected and method call doesn't return anything. However, I think you can get around it using argument constraints. Here's how I would do that second clause:
$factory->expects($this->once())
->method('addArgument')
->with($this->logicalAnd(
$this->isInstanceOf('Reference'),
$this->attributeEqualTo('attribute', $providerId)
));
The second item in the logicalAnd() is basically just checking the Reference object that is created to see if $providerId gets assigned correctly (I'm not sure what happens to $providerId in the Reference constructor, but I'm assuming it gets saved to an instance variable or something).
This sort of thing, however, is moving into the territory of testing implementation details of the Reference class, so tests like this are not great for maintaining SRP. All of this would be better solved by refactoring your code. Generally speaking, if it's hard to test, it is probably not the test suite's fault. If you are able to, consider changing things on that end first, rather than writing overly-clever tests.
Related
Given this code:
function testMe($a)
{
if ($a)
{
return 1;
}
else
{
return $this->testMe(true);
}
}
testMe() cannot be mocked, because then I cant call it. On the other hand, it must be mocked…
I'd say your question has some philosophical potential. I'll try to answer it the way you ask it but before, allow me to comment on your comprehension:
testMe() cannot be mocked, because then I cant call it. On the other hand, it must be mocked… [italics by me]
The unfinished sentence is wrong. You probably sensed it already because you didn't finish it. In a unit test you don't mock the unit. So you put the unit under test, and the unit is the method. That is the smallest part (unit) that can be tested.
What perhaps actually creates a bit of confusion is the recursion within the method.
So you actually ask how to unit-test recursion or a single method call within that recursion. But do you really need to test it?
I would say no. And that is because the recursion is an implementation detail of the method. From the outside it should not make any difference if you exchange the internal algorithm from recursion to a stack based loop for example.
But despite the fact I say you don't need that (and I hope you already have understood the argumentation I outlined), it technically is possible for your very specific scenario to test such a method-call without re-writing the code under test by re-binding $this. Then you can replace the subject under test ($this) with a mock when called. So that you have two methods: The one to test and the mocked one that is accessible via $this->testMe().
This could be done by instantiating the subject under test, create a mock, use PHP's reflection to obtain the closure of testMe() then re-bind $this on the closure to the mock and then call the closure for your test assertions.
I would not call this a unit-test any longer because as I outlined earlier, you're testing internals / privates, so you can use it more to actually test fragments of the recursion under certain circumstances and other similar detailed things that will more actually proof / debug fragments of code. You normally only need that under very specific circumstances when code is really high valuable.
Don't use your little confusion about the recursion to think this is an entirely important place to test on it's own. But if you want to get your fingers dirty, it's perhaps something worth to play with to learn about PHP reflection, closures and re-binding $this.
Background: I'm working on an MVC framework for some practice, and want to make sure everything is 100% unit tested.
The setup currently is to have an instance of the application class (Ex_App). The main script asks a Dispatcher/Router for a controller name. This controller name is the name of a class implementing Ex_Controller. The result is returned as an instance of Ex_Dispatch_Result. This result is passed to the Ex_App instance using an invokeController($dispatchResult) function.
And this is where magic happens. The listing below is an excerpt:
$controllerName = $dispatchResult->getControllerName();
... checks for validaty of class name ...
$controller = new $controllerName();
$controller->prepare($this);
I'm using PHPUnit to do my unit testing, and am able to mock the dispatch result, correctly check that validating the class name of the controller works. The problem is how to check if prepare is called.
I'd like to do something similar to:
$mockController = $this->getMockBuilder('Ex_Controller')
->setMockClassName('Invoke_Correct_Controller')
->getMock();
$mockController->expects($this->once())->method('prepare');
However since a new instance of Invoke_Correct_Controller is created upon calling invokeController, it will not be this mock and thus the expects() call is completely irrelevant.
I could make the Ex_Dispatch_Result class responsible for returning a controller and testing that, but before returning an instance I will need to verify the correctness of the class name and in my opinion that responsibility should be with the Ex_App class and not the "dumb shell" Ex_Dispatch_Result class.
Is there something I am missing in the PHPUnit framework that I could use to test the code here, or some useful pattern that could work in my instance? I feel passing around controller names scales way better than passing around instances of controllers from the start, requiring the initialization of every possible controller. So, I kinda want to stick to passing around names and using the Ex_App as a factory for the controller instance.
Maybe I'm just over-thinking part of this problem, but that happens sometimes. It's why a fresh look by a third party often works :-)
There are couple of things you could do:
Extract controller creation logic to separate class e.g. ControllerFactory, and then mock controller factory instance, so that it returns your $mockController.
Extract controller creation logic to separate method and use partial mocking.
Return $mockController from $dispatchResult->getControllerName(), which probably requires mocking of $dispatchResult or even something else.
If you want more detailed answer, please provide more code samples of your classes and methods.
I have a follow-up question to the one discussed here:
Laravel core method confusion
I am in the same situation as driechel (author of question above) has been before, currently getting used to Laravel 4 FW and examining the core. Although a precise answer has been given I still don't understand the logic and what is happening under the hood. So I would very much appreciate a further explanation.
I know this might be a duplicate but since I cannot post comments yet I'll give it a shot with a new question. Hope it' ok this way.
I have been looking at this from another angle starting at this article:
http://blog.joynag.net/2013/05/facades-in-laravel-4-and-static-methods-resolution/
When examining the call File:get() I finally end up at the Container class' share function which is called with this actual parameter share(function() { return new Filesystem; }.
What I just can't figure out is the use of $container. Especially at the second occurence within the closure:
$object = $closure($container);
Could you please clarify this again? Why is $container passed as a parameter here and what is actually contained in it? As far as I understand $closure at that point holds and executes function() { return new Filesystem; } which has no input parameter.
I am lost. Studied this and the PHP anonymous functions/closures now for two days straight and still can't figure it out. I neither understand the syntax of $closure($container) here nor the logic.
For reference, this is the share method # v4.0.5.
So, what's happening here. I'll explain it in a couple of steps.
Calling The Share Method
As you pointed out this method is called from service providers. So, the FilesystemServiceProvider calls this method which looks something like this:
$this->app['files'] = $this->app->share(function() { return new Filesystem; });
It's assigning the return value of this share method to a binding in the container. In a nutshell, that return value will be the new Filesystem instance that is returned in the closure.
So What Does Share Do?
The share method is just another way of defining a singleton in IoC container. All this can be a bit intimidating at first. Basically, Laravel itself is an IoC container. All the classes are bound as instances on the container. Sometimes these instances should be the same instance on every call.
If you take a look at the referencing method above on GitHub, you'll notice that inside the closure a static variable is defined. It then checks if that variable is null, and if it is it resolves the closure (this is the closure that returns our new Filesystem instance). Then it simply returns the variable.
Now, the next time you use File::get() it doesn't need to instantiate the Filesystem class again, because it's already been instantiated and stored in the static $object variable. So it simply returns the same object to you.
So! Really, you could replace the $this->app['files'] line with this, and it would still work.
$this->app->instance('files', new Filesystem);
99% of services actually use the share method though because working inside a closure allows objects to be instantiated with more complex dependencies.
Hope this helps.
In phpunit we can specify the method was called with particular
->with($this->equalTo('foobar'))
or any
->with($this->anything())
parameter.
But is there a way to specify that the method has been called without parameters at all?
This is the test I expect to fail:
public function testZ()
{
$a = $this->getMock('q');
$a->expects($this->once())
->method('z')
->with(); // <--- what constraint to specify here?
$a->z(1);
}
UPD:
The question has theoretical nature, so I have no any real life example. Some case it could be useful I can think of right now is:
public function testMe($object)
{
$object->foo();
}
And let's assume that testMe should (by design and by requirements) always call the method without parameters (assuming foo() has default ones). Because any non-default parameter (more precise: any parameter != to default one, which we don't know yet and which probably could change independently) in this case causes fatal consequences.
While rdlowrey is correct that with() doesn't make provisions for checking for no arguments passed, the problem doesn't lie with PHPUnit but PHP itself.
First, if your method doesn't provide default values, the interpreter will raise a fatal error if you don't pass any parameters. This is expected and not entirely relevant to the question at hand, but it's important to state up front.
Second, if your method does provide default values, calling the method without arguments will cause PHP to alter the call before PHPUnit gets involved to pass the defaults instead. Here's a simple test that demonstrates PHP inserting itself before PHP can check the parameters. It's key to realize that the mock class that PHP creates has the same signature as the mocked class--including the defaults.
class MockTest extends PHPUnit_Framework_TestCase {
public function test() {
$mock = $this->getMock('Foo', array('bar'));
$mock->expects($this->once())
->method('bar')
->with() // does nothing, but it doesn't matter
->will($this->returnArgument(0));
self::assertEquals('foobar', $mock->bar()); // PHP inserts 1 and 2
// assertion fails because 1 != 'foobar'
}
}
class Foo {
public function bar($x = 1, $y = 2) {
return $x + $y;
}
}
This means you can verify that either nothing was passed or the default values were passed, but you cannot be more specific.
Can you get around this limitation? You can remove default values from arguments when overriding methods, so you should be able to create a subclass and mock it. Is it worth it? My initial gut reaction is that this is a huge code smell. Either your design or your tests are doing the Wrong Thing(tm).
If you can provide a real-world, concrete example where you actually need to do this kind of test, it's worth spending some time pondering a solution. Until then, I'm satisfied with the purely academic answer of "don't do that." :)
PHPUnit mock objects can only use the ->with() constraint method to verify that the count or respective values of passed parameters match those passed to the mocked method when invoked. You can't use it to require that no arguments are passed to the mock method.
The mock verification process specifically checks that the passed parameter count and the associated values are compatible with those passed to the with constraint. Also, as you've probably seen, specifying the with constraint without any values won't work either; if with receives no parameters it won't add any parameter constraints for verification.
You can see the actual PHPUnit_Framework_MockObject_Matcher_Parameters::verify method used to verify mock method parameters in the linked github source.
If validation of no passed arguments is a requirement you'll need to specify your own mock class to verify such a condition outside the PHPUnit mocking capabilities.
For example lets say I have a set of classes and methods to do so:
$obj->method1()->method2();
Is there anyway for method1() to know with in itself that its the first method being called or for method2 to know that its the last?
Some more details
I just want to be able to build a set of these calls so that it either returns an instance of itself if the call to the method isnt at the end of the chain or return something different if its at the end.
For example
$obj->method1()->method2(); #Here method 2 will return lets say a string.
$obj->method1()->method2()->method3(); #Since method2 isnt at the end of the chain, it should return an instance of itself (or another object) here so that the chain could continue.
EDIT: anyone whoz trying to do this - it is a bad design pattern.
This does seem to be a duplicate. Refer to this question for more answers.
Not out of the box, not even with a Stack trace.
I guess you could put something together using constants or global variables:
Don't try this at home!
$GLOBALS["chain"] = array();
$obj->method1()->method2(); // method1 adds member to $GLOBALS["chain"],
// array_push($GLOBALS["chain"], __FUNCTION__);
// method2 does the same...
print_r($GLOBALS["chain"]);
That would give you the full chain - not yet which one is the last one, to do that, you would have to pass a flag to method2().
But it would be horribly hacky and pollute your code.
Is there a specific reason you need this for?
All you could do is find out which methods have been called so far, by setting some kind of global state in the class. But you can't find out what methods are being called after a method, and you wouldn't be able to tell the difference between methods in one chain and methods in another:
$obj->m1()->m2();
$obj->m3(); // You would think that m1() and m2() came before this in the same chain
You would need to have a method at the end of each chain to clear the global state in the class.
Since it seems you need to see which method comes next in a chain, this won't work for you.
I would say that this is a really bad design pattern, at least for PHP (and every other language I've worked in). Each method should do one thing only. If you need a method to either return a string or an object depending on what you need it for later, you are doing something wrong.
Granted, I have done something like this before. It was a meta-information class for images submitted by users -- you could set it up like this:
$meta = new ImageMeta();
$meta->first_name("foo")->last_name("bar")->email("baz")->id("guid");
But, if you did this:
$meta->first_name();
it would return a string. The default value for the first parameter was NULL, and if the method got NULL, it returned a string. Otherwise it set (and escaped) an internal value and returned $this.
At first I thought it was kind of cool, but it turned out to be a mistake. I hate using that class now. Just make one method/function do one thing only and you will be much happier.
I don't think this is possible, no -- at least, I've never seen anything about this.
(Out of curiosity : why would you need that ? Maybe it would be possible to use onther solution to solve your actual problem ?)
The only way this is possible is to let the methods save some global state.
If both methods are in the same class, you could add a variable to the class and let each class set a unique value.
But the question is if this is desirable. This kind of behavior is often not very smart in the long run.