PHPUnit - Recommendation when we have logic seperated from Controller
Hope you do fine guys.
I would like to mostly have an open conversation with you . A thought that has been on my mind again and again the last weeks.
Suppose that you have 1 controller that is calling a service's function which contains business logic and returns a response.
Which of the following you consider as a best practice while testing this, and why?
Write a Feature test for the Service function by it's own. To test the controller's API call, mock the Service & assert the execution of corresponding functions.
Write a feature test without any mocking, test the full API call with real data.
@ninj4df The point of “services” is to extrapolate logic into its own class and method(s) so that it can be used in multiple places. Therefore, yes, I would have a test for the service itself as well.
For the controller, you’re testing a specific response is returning but not necessarily testing the logic, so you can mock the service in that instance.
@Ninj4df I dont see any issue with testing without mocking. If it's red route (ie primary function or high business value) then I would happily add a test that hits the live class.
I would recommend you have a test class for every class you write.
Test class should directly test each public method in the accompanying class. Private methods will be tested as part of public tests.
A controller that calls an additional class, can have the service class mocked. You'll know what you'll be putting in and getting out of your service classes methods so that will go into the mock.
Depending on how much work the service class does, you may choose to write a feature test not mocking the service class's methods but that should be quite light as you'll have covered all the options via your direct test class.
My main consideration is that most of the times it feels like "double work" for nothing, when we test both Services isolated + Controllers (without mocking) logic. That's how the whole thought came into my mind to be honest. So I am searching for a way that really makes sense.
@Ninj4df it only feels like double work if you are writing tests after you are writing your code.
if you use your tests to help you build out your classes, then you'll see more value. Write a test to describe how you expect your code to behave and then write code to pass that expectation. When the test passes, write another failing test to cover new functionality and then more code.
@Ninj4df a good way into TDD is if you are trying to bug fix. A user will report an issue with your code, and the first thing you should do is to write a failing test that fails in the same way the user has reported. Once you have written the fixing code, your test will pass and then you know you can ship the fix.
Feature test for API call, without even testing what service does, just testing real-life scenario and expected API call result. You may use Mocking but instead I would do...
Unit (not feature) test for Service itself, for different scenarios if needed
But it's my personal preference, not any rule or the "best practice".
@PovilasKorop sorry Povilas, you would use Mocking or not? I didn't understand the last sentence of your 1st bullet. (propably because of pure English so sorry for that)
Thank you very much for the answer, and btw I also love your videos man :) You have inspired me so much on the framework.
@Ninj4df great to hear about inspiration. I would not use mocking, the service behavior would be covered by UNIT tests.
Only if the services are not separated enough to be unit tested, then it makes sense to mock them inside of feature tests. But that may be a sign that your code is not ideally structured for testing.