framework: "app()->makeWith(..." does not work with "app()->instance(..."
- Laravel Version: 5.6
- PHP Version: 7.1
Description:
function app()->makeWith(...
does not work with app()->instance(...
It should return prepared instance, but it creates a new object all the time.
It makes Mocking impossible. Unit-testing concept is not working.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 1
- Comments: 23 (14 by maintainers)
You can bypass this with
offsetSet:In case someone else is looking for this. You can mock it like this in your tests. Use bind() instead of instance()
And it will use the Mock.
Yes, it does.
https://github.com/laravel/framework/blob/56a58e0fa3d845bb992d7c64ac9bb6d0c24b745a/src/Illuminate/Container/Container.php#L592-L602
@mfn, wow thank you very much! Never expected something that obvious! Will you believe I worked a full day on this one… So in essence @sisve was right, expecting an already cached instance of
ApiServicewhen he says:The order in your
setUpis wrong:AnotherServicewhich usesApiServiceso it will immediately create non-mocked instance ofApiServicefor that serviceSwitch the two lines and it should work.
My first thought is that you have already resolved and cached an AnotherService somewhere. Is it perhaps a singleton registered from within your service provider? Then it would keep using whatever reference to ApiService it had from the beginning, and not know about any mocked instances introduced in the Container at a later time.
I’m using mocked services in
setUpall the time, no problems.How does your
setUplook exactly?How does the code, which resolves the
ApiServicelook like (or the constructor ofAnotherService)?Is there any news on this one?
What is going on? Why the issue is closed when the bug persists?
This does not feel right.
Getting some kind of instance from the service container with dynamic parameters is always a bit of hybrid and can pose some challenges, one of them is the problem of mocking.
For tests, you can use a factory class which will then create your instance based on your parameters. Which means, you return a mock for the factory which then is responsible for creating your mocked actual class. Sounds a bit complex, but in practice it’s easy:
You then mock
ConreteFactoryand return viayourOwnMakewhatever you want, and it can also be dynamic based on your$argsMakedoes not support parameters in laravel 5.6Laravel ignores differences between
bindandsingletonif there is aninstanceprovided. It is working great for mocking. I think it should also ignore parameters if the instance is given. For mocking purposes the provided instance should be different from what is built using some parameters. Laravel does not care about instance that is set byapp()->instance(..., it may be an instance of a different type, why should it care about parameters?