-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Cannot get service in tests #36147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
See #28528 I'm guessing the service |
Yeah, you're right... While I understand the argument that there is no point in testing a service which isn't used anywhere it is quite confusing. The thing is that I added a new service and wanted to cover it by tests before actually using it in the app. |
In which case, why do you need to load the service from the container? |
@blowski ? I just explained that in my last comment. Wanna have the service tested before I start using it. |
Why do you need to load the service from the container, instead of instantiating it with |
lol because it has non-trivial dependencies obviously |
Without seeing your exact use case, it’s hard to comment specifically. Let me confirm I’ve understood what you’re saying. It sounds like you’re building a class and want to test it before integrating it with the rest of the project (standard TDD approach). Because you haven’t yet configured anything else to depend on it, it’s not available from the container, even when all services are set to be public. So you’d like it to be available from the container anyway. Have I got that right? You also mentioned that it’s hard to instantiate the service in the test using standard PHP Personally, I would instantiate the service using simple PHP`, because then you’re not depending on and having to load the framework.
If it’s hard to do that, I would first try refactoring to make it easier. If the dependencies themselves are hard to instantiate I guess you could load those from the container, and pass them to the service. For example:
I definitely don’t see this as a bug in the service container. If you really want to do this, you can define it yourself in the service yaml file and get rid of the definition when you no longer need it. |
Yeah.
It's not hard to do, but literally impossible. We're getting quite off-topic here since you're questioning my needs but alright, let me explain. The service in question has a dependency on EntityManager and it is a service responsible for fetching the correct data from the database. I need to test that the SQL queries are returning the intended results. I think you'll agree that EntityManager is not something I can just create using
Yes, this is something I can do and actually did in my case. I just don't exactly like it because I don't wanna care about the service dependencies in the test. I'd much rather just fetch it from the DIC. Also there are cases where the arguments are not actual services but the services are wrapped by let's say symfony/cache adapters. So while not my case this time, even this construction may sometimes get very non-trivial compared to fetching the service I wanna test.
I don't see it as a bug per-se either but the exception is extremely confusing and it's difficult to find out the "actual" reason why the service was removed. If the exception message at least said that the service was removed because it was never used then it would be somewhat acceptable. The current state is definitely not. |
So when you’re trying to load the service in an integration test, the container is returning a confusing message about the service being missing. A message like “this service was removed from the container because it’s not used anywhere” would make it easier for you to debug why you’re not able to load it in the test. Did I understand correctly? |
Yes. I'd still prefer for the service to be available but at least knowing why it isn't would be better than the current WTF state. |
From what I can see, you are trying to do here a unit test... So mock the dependencies and be done with it. If you have too many arguments, then it means you are breaking the single responsability principle which usually means your service does too much. |
@Taluu 🤦♂
From what I see you didn't bother to read:
How would you unit test a service responsible for fetching database data? Of course I can't mock anything. That would make the test completely pointless. I need to verify that the SQL queries work as intended and of course I can only do that when testing against a real database. |
Thanks for your awesome reaction, as it really helps me helping your. Anyways. What you are looking for is a functional / integration test... You must instantiate your service with a Otherwise it's "pointless" as you said, as you have no idea how your service is instantiated. 🤷♂ |
@enumag for now as stated here the only solution is to actually make sure your service is used or mark it
Edit: or define a |
The public alias is the recommended way here. |
Personally speaking, I think integration tests should only be testing public services anyway. @enumag I'm going totally off-topic from your original bug report, but perhaps it might help solve it in a different way. I think most of us have run into this problem in our own projects, and in my own work, I approach this by using interfaces on my repositories.
These tests are quicker to run and less flaky. The only place I actually test the queries are running correctly is in full functional tests (i.e. WebTestCase tests) and Doctrine repository tests. Unit tests always use the in memory implementations. Where I have other complex services as dependencies, I use a decorator so I can inject stub implementations in unit tests, and the real thing everywhere else. There's a good chance that, for some reason, you've already come across and rejected this pattern but I thought I'd leave it here for anyone else struggling with the problem you mentioned. |
@blowski You don't understand. The service I'm testing effectively IS a Repository. (It's just named differently and doesn't extend EntityRepository because of personal choice (no reason to use inheritance for repositories imo.) As for services that are calling this class and actually using the data, I'm testing them differently with in memory data of course. What I'm trying to test here are the actual SQL (or DQL) queries since they're too complex to leave them without tests. |
You're right, sorry, I didn't realise these were repository services you were trying to test. I agree with you about not extending from EntityRepository, so my repository tests typically look like this:
|
Mine too. :} Ok, so I really think you should either use a public alias or even better, instantiate them yourself. Do not test the container instantiation, but your object (you can stlll fetch the entity manager from the container...). |
Closing as this has been answered now. Public test aliases to the rescue - or any other options. |
…terj) This PR was merged into the master branch. Discussion ---------- No longer recommend injecting the service container Fixes #13469 I think it makes sense to no longer document injecting the service container. Service subscriber is the better alternative in any case. I actually also thought about removing setting a service public at all. But let's keep it for now (it is sometimes usefull in tests see e.g. symfony/symfony#36147 and #12647 . It's also a bit weird to have a "Public Versus Private Services" section that only discusses "private" services Commits ------- 156ac13 No longer recommend injecting the service container
Symfony version: 4.4.5
I'm starting a new project (using SF 4.4 because it's LTS) and in my tests I'd like to use the new feature that enables getting services easily in tests.
However even when doing everything as described on a completely fresh project without any hacks I'm still getting this error:
The exception stack trace contains
vendor/symfony/framework-bundle/Test/TestContainer.php:106
which proves that the "special container" as described in the post is indeed used. But I still can't get the service.What else do I need to enable to use this feature?
The text was updated successfully, but these errors were encountered: