Does anyone know how to use mocks with the REST module and Laravel5 module as the beackend?
It seems that the application is being refreshed every time I do a sendXXX call, which wipes out any mocks I've setup.
The Laravel 5 module indeed refreshes the application between each request. But what are you trying to do that you need mocks in functional tests between requests? This probably is not a very good approach, whatever you want to achieve.
I'm working on a application that talks to several external services. I want to mock the responses of these services rather than hit them from the automated tests.
Isn't it the whole point of dependancy injection to be able to provide alternative implementations of services without having to mix test and production code?
Can't you just separate your requests in a test for each request?
Another option is to set your mocks in a service provider. You can just check if you are running in the test environment and if so add your mocks to the dependency injection container.
I did end up configuring the service provider to create the mocks, but it's a bit of a code smell. I'm configuring test requirements out side of the tests, and it doesn't provide much flexibility in how the mocks respond.
I understand why the app refreshes on each call. It's just a shame there's no way to configure the app from the tests before the call.
I am open to suggestions, what do you think would be a nice way of doing this? Some sample code of how you would like to use such a feature would be great.
@janhenkgerritsen I'm having the same issue. Want to mock a repository that collects data from an external API to avoid hitting the external API in tests.
I tried to hack something together in my functional suite:
<?php
use App\Integrations\Vendor\Repo;
$I = new FunctionalTester($scenario);
$I->wantTo('Import products from external API into my app');
$repo = Mockery::mock(Repo::class);
$repo->shouldReceive('all')->andReturn(['foo' => 'bar']);
$I->bindService(Repo::class, $repo); // or bindInstance
$I->amOnRoute('import'); // in here, repo->all should be called, but the mock is not called, the actual repo is used instead
// ... test that I see foo => bar
In my FunctionalHelper.php I tried to add this:
public function bindService($abstract, $instance, $shared = false)
{
$laravel = $this->getModule('Laravel5');
$app = $laravel->getApplication();
$app->bind($abstract, $instance, $shared = false);
$laravel->setApplication($app);
}
// Also tried similar bindInstance:
public function bindInstance($abstract, $instance)
{
$laravel = $this->getModule('Laravel5');
$app = $laravel->getApplication();
$app->instance($abstract, $instance);
$laravel->setApplication($app);
}
Problem is that the mock is never used, only the actual Repo class.
Here is a solution that overrides the connection class to achieve this:
http://stagerightlabs.com/blog/using-mockery-with-codeception-and-laravel-4
I have googled a bit and others are asking about the same, for instance here:
https://laracasts.com/discuss/channels/testing/ioc-container-mocks-and-codeception-integration-testing
I will look into this issue after I come back from my holiday.
I think we can use approach similar to @torkiljohnsen uses to register his mocks and apply them after each request.
We can have
haveMockedService() methodhaveMockedInstance before a request is made all mocked things are injected inro application
And probably a method to disable mock:
disableMock($serviceOrInstanceName) The Laravel IoC container has the following methods to register bindings:
// Register a binding
public function bind($abstract, $concrete = null, $shared = false);
// Register a binding if it hasn't already been registered
public function bindIf($abstract, $concrete = null, $shared = false);
// Alias for bind($abstract, $concrete, true)
public function singleton($abstract, $concrete = null);
// Register an instance
public function instance($abstract, $instance);
// When $concrete needs $abstract give $implementation
public function addContextualBinding($concrete, $abstract, $implementation);
I think we can skip bindIf for tests, but we should have methods for the other types of bindings. I think we should add the following methods:
public function haveMockedService($abstract, $concrete);
public function haveMockedSingleton($abstract, $concrete);
public function haveMockedInstance($abstract, $instance);
public function haveMockedContextualBinding($concrete, $abstract, $implementation);
As for a disableMock method, I don't think such a method is really necessary. If you want to mock some service in a test, you probably want it mocked for the whole test.
What do you guys think of this?
You could name it something general instead of "service", since the
container can hold all kinds of bindings.
Also think you should avoid calling it "mock", since we could be injecting
all kinds of things as test doubles, like a dummy, mock, stub, fake, spy,
etc.
Why not just reuse the Laravel naming to make things very obvious?
$I->haveBinding/haveInstance/haveSingleton/haveContextualBinding ?
fre. 17. jun. 2016 kl. 17.40 skrev Jan-Henk Gerritsen <
[email protected]>:
The Laravel IoC container has the following methods to register bindings:
// Register a binding
public function bind($abstract, $concrete = null, $shared = false);// Register a binding if it hasn't already been registered
public function bindIf($abstract, $concrete = null, $shared = false);// Alias for bind($abstract, $concrete, true)
public function singleton($abstract, $concrete = null);// Register an instance
public function instance($abstract, $instance);// When $concrete needs $abstract give $implementation
public function addContextualBinding($concrete, $abstract, $implementation);I think we can skip bindIf for tests, but we should have methods for the
other types of bindings. I think we should add the following methods:function haveMockedService($abstract, $concrete);
function haveMockedSingleton($abstract, $concrete);
function haveMockedInstance($abstract, $instance);
function haveMockedContextualBinding($concrete, $abstract, $implementation);As for a disableMock method, I don't think such a method is really
necessary. If you want to mock some service in a test, you probably want it
mocked for the whole test.What do you guys think of this?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Codeception/Codeception/issues/2904#issuecomment-226803913,
or mute the thread
https://github.com/notifications/unsubscribe/AATaiS0gry2ga_jtqnOwoYn2SjY72ztjks5qMr_xgaJpZM4HwfLa
.
I agree with @torkiljohnsen about the naming. What do you think @DavertMik?
I like it to :+1:
I implemented the functionality and merged it into the 2.2 branch. I also added tests to the sample application with commit https://github.com/janhenkgerritsen/codeception-laravel5-sample/commit/3e4b49fbecbf6da69e47f02717931e25634e8b75.
If you want to use this new functionality right away and not wait for Codeception 2.2.2 you can use 2.2.x-dev as your composer version constraint for Codeception.
Hi everyone.
Sorry, maybe I've missed something. But I have only one question, and couldn't find any answers.
Does it work with ApiTester?
As long as your API tests are functional tests it should work.
I don't understand. What do you mean? I have api tests and functional tests. I understand that I can mock service in functional tests. But what if I need mock service in api tests.
Or you mean that I should testing API in functional tests?
You can test your API with functional tests, for that you can use the Laravel5 module. But you could also test your API with acceptance tests, for which you can use the WebDriver module. In that case you should not use the Laravel5 module and you will not be able to use the functionality described in this issue.
For more details on the difference between functional tests and acceptance tests check out the documentation:
Most helpful comment
I implemented the functionality and merged it into the 2.2 branch. I also added tests to the sample application with commit https://github.com/janhenkgerritsen/codeception-laravel5-sample/commit/3e4b49fbecbf6da69e47f02717931e25634e8b75.
If you want to use this new functionality right away and not wait for Codeception 2.2.2 you can use
2.2.x-devas your composer version constraint for Codeception.