I just started writing tests in the context of Symfony framework, and I’m wondering when to just use TestCase class over KernelTestCase.
A bit of context : I need to test my custom services which are called by my controllers. All the business logic lives inside my services.
I have methods that are used for crud actions, others for email sendings etc…
I need to know when to use TestCase over KernelTestCase because the main difference I see is that with KernelTestCase you can call the container instead of instantiating your services, so when is TestCase more appropriate than KernelTestCase and the other way around ?
The official documentation says :
An integration test will test a larger part of your application
compared to a unit test (e.g. a combination of services). Integration
tests might want to use the Symfony Kernel to fetch a service from the
dependency injection container.
So does this mean that If I have a service that uses many other services I need to use KernelTestCase ? If so, what’s to borderline to go with KernelTestCase over TestCase ?
Hope I’m clear.
>Solution :
So does this mean that If I have a service that uses many other services I need to use KernelTestCase ?
Not necessarily !
By using a TestCase (from PHPUnit) you can easily mock dependencies (instanciate fake objects by extending them) and even make expectations on their method calls:
$dependency = self::createMock(MyDependencyService::class);
$dependency->expects(self::once())->method('someMethodName');
$service = new Service($dependency);
$service->testedMethod();
Here we expect the $dependency mock object to have its someMethodName() method be called once. If not, the test will fail. You can make more complex assertions about arguments and define the returned value.
Using KernelTestCase (from Symfony), you have access to services from the service container. This is very useful when you really need a service and not a mock object that does not really do anything.
For example, you could request the serializer to transform some JSON input into DTOs:
$serializer = self::getContainer()->get(SerializerInterface::class);
$service = new Service($serializer);
In some cases, you can even get your fully configured service from the service container, or replace a service in the container before doing so.
Note that using KernelTestCase does not imply the use of the testing service container in every test, you may only need it in a single test.
It really depends on the behaviours you want to test and the dependencies of your service. If you need to get real services to test your custom one that you cannot really instanciate yourself, go with KernelTestCase, but if you can avoid it (using the Kernel and service container can slow your tests suite), go with TestCase and use mock objects.