PHPUnit prophesize a method without exact arguments - php

I'm mocking a UserRepository class using prophecy to ensure that when a POST request to /user is sent, that the create() method on UserRepository is fired.
$repository = $this->prophesize(UserRepository::class);
$repository->create()->shouldBeCalled()
The only problem is that the create() method sends Request data as an argument to the repository for some serious tweaking of the inputs before doing anything. How do I mock the create() call without telling prophecy what the arguments will be?
Or is this just really bad practice on my end and the Request data should never be passed to the repository?

use Prophecy\Argument;
$repository->create(Argument::any())->shouldBeCalled()

use Prophecy\Argument;
$repository->create(Argument::cetera())->shouldBeCalled()
any() matches any single value where cetera matches all values to the rest of the signature.

Related

PHP method mock check for an argument passed to the method

I am using the Phpunit for unit testing and its mocking framework. I have a mock for a method:
$myProcessor
->expects($this->once())
->method("myMockedMethodName");
I would like to validate one of the arguments passed to it.
For example, my function takes arg1, arg2, arg3. I would like to check only for the arg2.
How to do with PHP mocks?
You'd use the with() method as explained in the docs (https://phpunit.readthedocs.io/en/latest/test-doubles.html#test-doubles-mock-objects-examples-subjecttest2-php)

How does PHP function dependancy work?

I have an example here from the framework Laravel.
class UserController extends Controller
{
public function store(Request $request)
{
$name = $request->input("name");
}
}
What I don't understand is that Request is explicitly defined within the function signature of store().
Couldn't php's type inference figure out what is being passed into the function?
Would this even be considered dependency injection?
This is method level dependency injection. The Request is being passed into the store method, instead of the store method knowing how to create the Request object.
The type hint in the method signature does two things.
First, for plain PHP, it enforces the fact that the parameter passed to the store method must be a Request object, or an object that inherits from Request. If you attempt to call the store() method with anything other than a Request object (or descendant), you will get an error.
Because of this strict type enforcement, we know that the $request parameter must be a Request object (or descendant), and we can depend on its public interface being available for use (you know the input() method will exist).
Second, for Laravel, it tells the Laravel container what type of object this method needs, so that the correct object can be resolved out of the container and passed to the method. Laravel's controller methods are called through the container, which allows automatic dependency resolution of method calls.
If you were to remove the type hint, this would cause two issues. At an abstract level, it would allow you to pass any type of object, or even scalar values, to the store() method. If you attempt to call input() on a string, you're going to have problems. At a more concrete level, this will break Laravel's automatic dependency resolution of controller methods. Without the type hint, Laravel can't know what object the method requires, so it won't pass in anything, so in reality you'd get an error saying that you can't call input() on null (or an error saying the store method requires one parameter; not sure, didn't test).

Mocking SecurityContext in Symfony2 using PHPUnit

These are my mocks:
$this->user->method('getCustomerId')
->willReturn($this->customerId);
$this->userToken->method('getUser')
->willReturn($this->user);
$this->securityContext->method('getToken')
->willReturn($this->userToken);
$this->securityContext->expects($this->once())
->method('isGranted')
->will($this->returnValue(true));
And this is the code of the class I am testing:
$token = $securityContext->getToken();
$isFullyAuthenticated = $securityContext->isGranted('IS_AUTHENTICATED_FULLY');
It throws the error:
Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException: The security context contains no authentication token. One possible reason may be that there is no firewall configured for this URL.
I have no idea what to do at this point, I though mocks intercepted the call to methods and returned whatever I wanted. But in this case is seems the isGranted methods is not being mock
I figured out that the problem is that the isGranted method is final, so it's imposible to mock, the workaround the problem was to mock all the attributes of SecurityContext so that when the method is call it returns my desired output, instead of intercepting the call with a mock method.
Try using willReturn instead of will and add the with
So try this:
$this->securityContext->expects($this->once())
->method('isGranted')
->with('IS_AUTHENTICATED_FULLY')
->willReturn(true);
Instead of this:
$this->securityContext->expects($this->once())
->method('isGranted')
->will($this->returnValue(true));
Hope this help

Mockery "shouldReceive" yet method doesn't exist

I'm trying to understand Tests and Mockery a bit more with Laravel. I have a repository pattern setup, which my controller users. I want to test my basic getAllUsers()method:
public function test_get_all_users_method()
{
$repo = Mockery::mock('Acme\Repositories\User\UserRepository');
$repo->shouldReceive('all')->once()->andReturn('foo');
$controller = new Acme\Controllers\Api\UserController($repo);
$response = $controller->getComponents();
$this->assertEquals('foo', $response);
}
As I understand it, I'm mocking my UserRepository, and I expect my UserRepository to have it's all() method hit. This returns some dummy data and I expect to see this in my response output.
So that works fine. The all() method exists in my Eloquent implementation of the repository. However, if I remove the all() method, the test still passes... Why would it? Surely the test should fail.
If this is normal, I'm struggling to understand why I'd test my controller like this, since I could pass any old method name into it even if it exists or not.
Cheers
That's how mockery operates by default, I like it that way because it allows me to develop by wishful thinking, i.e. I wish my UserRepository interface had an all method.
You can tell mockery to disallow it though, it's a bit ugly, but you can put this in your test bootstrap file:
\Mockery::getConfiguration()->allowMockingNonExistentMethods(false);
You could also set this up to control it with an environment variable or something, so you allow mocking non-existent methods during normal use, but prevent it on your continuous integration run etc.

Meaning of #method && #Command annotation in aws php sdk

I was looking into the codebase of Amazon AWS PHP sdk and found that, several methods in comments are declared as #command such as the one below(link: https://github.com/aws/aws-sdk-php/blob/master/src/Aws/S3/S3Client.php):
* #method Model getObject(array $args = array()) {#command S3 GetObject}
Can anyone please explain how this actually works? I want to know the actual working mechanism inside 'getObject' method call. Thanks in advance.
Methods such as getObject() are dynamic methods instead of static methods. The real call is getCommand('GetObject'), but the class's __call() method handles the real work.
Every service in the SDK has a Model Definition. The getCommand() method takes the inputs and maps them to the Model Definition and makes the right request.
So, think of getObject() as a convenience method, that is constructed dynamically instead of statically.

Categories