Ninj4df's avatar

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?

  1. 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.

  2. Write a feature test without any mocking, test the full API call with real data.

  3. Do both of the above?

  4. Any better approach on your mind?

Write your thoughts please :)

0 likes
11 replies
martinbean's avatar

@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.

1 like
automica's avatar

@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.

1 like
martinbean's avatar

@Ninj4df I don’t really know how to convince a third party not present in the conversation, I’m afraid.

If they’re that paranoid, you can run your test suite with test coverage and show that both the controller and the service class are covered by tests.

automica's avatar

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.

1 like
Ninj4df's avatar

@automica sounds awesome.

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.

automica's avatar

@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.

Red, Green, Continue to refactor.

Ninj4df's avatar

@automica thanks for the tip, I have to try that. To be honest, yes, we do not do TDD but I want to try this soon or later.

automica's avatar

@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.

1 like
PovilasKorop's avatar

@ninj4df I would write two tests:

  1. 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...
  2. 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".

1 like
Ninj4df's avatar

@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.

PovilasKorop's avatar

@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.

1 like

Please or to participate in this conversation.