Inject Laravel Input property into Mockery session object - php

I'm working on an existing Laravel app and trying to start building out a test suite for it. I'm using the Mockery library to mock the dependencies of the class I'm testing but I've hit a roadblock I can't seem to get around.
$leadRepositoryInterface = m::mock('CRM\Storage\Lead\LeadRepositoryInterface');
$response = m::mock('ColorJar\ApiResponse\Response');
$object = new LeadsController($leadRepositoryInterface, $response);
I get an error when I run the preceding code because the parent class of LeadsController checks Input::all()[__currentUser] and crashes because Input::all() returns nothing.
I need to set the Laravel Input facade variable(I'm sure I'm misusing terminology there, sorry) to any user in my system but I don't see anywhere in the Mockery docs on how to set a property of a mocked object, I only see how to set expectations and return values. How would I do this? Will Laravel allow me to set the return of Input::all()?

You can't mock the response from the Input facade but you can mock the underlying class which is Request. You would then do something like this:
Request::shouldReceive('input->all')->andReturn('someValue');

Related

Test factory method

Write tests to coverage 100% code is something we should attempt to achieve. But I came up with situaction where I don't know how to test method (factory method):
public function getDocument(){
$document = new Document();
$document->settings(new Settings());
$document->filesystem(new Filesystem('e:'));
return $document;
}
Purpose of that method is shortcut to create document, without everytime write 3 lines.
How to test this method?
Or maybe this is situation why we have #codeCoverageIgnoreStart block? Exactly for that reason PHPUnit provide this kind fo annotations.
EDIT:
The main idea behind this method is make client life easier. Nothing more, no configuration etc.(but the method will be good place to do it).
//I don't want bother client with Settings() and Filesystem('e:')
$document = new Document(new Settings(), new Filesystem()); //NO
$document = Files.getDocument() //much easier and shorter.
//Changing API to getDocument($var, $var) make no sense, the same thing I could have normally.
$document = new Document(new Settings(),new Filesystem('e:'));
Maybe I should thing about if I really should provide that method, user who want use document should know of dependences, it shouldn't be hide.
What this method does? Returns initialized Document object. So all you have to verify is that the returned value is a Document instance and that it has Settings and Filesystem objects set. Easy if you have getters for those, otherwise you have to access the respective properties.
The test may sound very basic, but it does test what it needs to. When you refactor your code in a way that the settings and filesystem are injected, the test will still tell you if the document has those properties set at all.
It's called unit testing because you are testing a unit, not an object or a method. If your unit has multiple classes, let it be. There's no need everything to be injected and there's no need everything to be mocked - those things ease testing, but in certain cases it's even better not to mock them
Inject your dependencies (Document, Settings, Filesystem) via the constructor, then use test doubles as appropriate.
Also reconsider your 100% coverage policy, it's definitely not clear that it's actually a good thing.
Pass the dependencies to the factory method, initialize the new object inside, and configure it properly. In the test, the dependencies will be mocks instead of real objects.
method 1
Pass factories that allow to create the dependencies:
public function getDocument(SettingsFactory $sf, FilesystemFactory $ff){
$document = new Document();
$document->settings($sf->getSettings());
$document->filesystem($ff->getFilesystem());
return $document;
}
In the test, you should:
create Settings instance or mock and a SettingsFactory mock that expects one call to getSettings and will return the Settings instance
create Filesystem instance or mock and a FilesytemFactory mock that expects one call to getFilesystem and will return the Filesystem instance
call the DocumentFactory method, passing the factories. Check that a Document object is returned
check that the objects assigned to Document are the same that you configured the mocks to return
A variant on this is having the getSettings and getFilesystem as methods of the Document factory. In that case you should create a partial mock of the Factory, and set the expectations on it. So the real getDocument method is called, but when getSettings and getFilesystem methods are called, you return controlled instances.
method 2
Pass the actual dependencies:
public function getDocument(Settings $settings, Filesystem $filesystem) {
$document = new Document();
$document->settings($settings);
$document->filesystem($filesystem);
return $document;
}
In the test, you should:
create Settings instance or mock
create Filesystem instance or mock
call the DocumentFactory method, passing the Settings and Filesystem. Check that a Document object is returned
check that the objects assigned to Document are the same instances that you passed to the factory method
Kind of I find answer: this code isn't testable.
Wherever you have new XXX(...) in a method under test, you are doomed.
More:
https://stackoverflow.com/a/7763207/2490611

Issue with generating a mock for an interface

I'm currently trying to build mocks for an interface (defined here as the Policy class) which only has one method, check; as seen below I'm basically just replacing it with a stub method which always returns a known value:
$mockBuilder = $this->getMockBuilder(Policy::class);
$allowMock = $mockBuilder->getMock();
$allowMock->method('check')->willReturn(Vote::ALLOW);
It registers as an object implementing Policy, as it should, but whenever the check method is called it only ever returns null. What am I doing wrong in my construction here?
Not sure if that solves your problem, but to mock interfaces, you should use getMockForAbstractClass():
$allowMock = $mockBuilder->getMockForAbstractClass();

How to mock an Eloquent Model using Mockery?

I'm trying this:
$this->dsMock = Mockery::mock('Eloquent', 'API\V1\DataSet');
$this->app->instance('API\V1\DataSet', $this->dsMock);
$this->dsMock->shouldReceive('isLocalData')->once()->andReturn(true);
Then, inside the class under test:
$test = DataSet::isLocalData($dataSetId);
However, the DataSet class is not being mocked. It's still trying to access the database. Why?
The likely problem is Laravel's unfortunate over use of Façade's (which are also factories). If DataSet was already instantiated using the Façade, it will keep returning the same class, you won't get a mocked version.
I can't remember off hand if you can instantiate your class without using the Façade in Laravel. You have to remember that when you call DataSet statically in the application, you're actually not referencing API\V1\DataSet but something else that manages it.

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.

Mocking a method on dynamically allocated instance?

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.

Categories