The framework structure is designed to avoid any obstacles to code testing built on it. This applies to all types of controllers, standard services, and custom framework functions.
The testing approach depends on the usage type of the services, which may be a corresponding class with static methods such as Hleb\Static\Service::method() for built-in framework services, or DI, referring to service (and other object) injection into class methods and constructors.
Dependency Injection within the framework is limited to objects created by it, including controllers, middleware, commands, events, and objects created by the service known as DI.
A simple example of a demonstration controller with DI:
Suppose you need to ensure that the controller returns the text 'OK' without sending a message to the logs.
Here, the logging class is replaced by a class with the same interface, but its methods do not send anything to the log.
It is assumed that one of the special testing libraries (such as github.com/phhleb/test-o) is used, with checks implemented through it.
Now, let’s invoke the method of an arbitrary class through the DI service (specifically the framework service, not the architectural pattern itself):
In this case, the logging service will be injected from the container, and the message will be logged. Let’s modify the method invocation for testing:
Now the class has been tested without logging occurring. You can substitute any DI object with a custom class designed for the required behavior, making it convenient for testing.
The built-in services of the HLEB2 framework can be accessed with static methods such as Hleb\Static\Service::method(). This approach simplifies access to services but can complicate testing of the modules containing them, although it is still feasible. Here's an example with logging:
The example shows how the service state was replaced with a test object and then reverted to its initial value. To prevent this approach from being used outside of tests, in a production project, the configuration parameter 'container.mock.allowed' in the /config/common.php file is set to false.
To run tests that initialize the core of the framework, you may need to replace some or all services in the container with test objects. To do this, simply implement your own service and assign it based on a condition (in the example, this is the global constant APP_TEST_ON):
Several built-in framework functions that simplify service calls, such as the logger() function, are implemented through tested service calls, in this case, as a wrapper around Hleb\Static\Log.
In controllers, middlewares, commands, events, and other classes inherited from Hleb\Base\Container, the container can be accessed as $this-container. If you choose this method of using the container (mixing various methods within a project would look odd), special initialization of the object constructor is required for testing.