The preceding code makes explicit hardcoded dependencies between classes. To work around this, CDI can be applied. This has been used in other languages, such as Java. In the following examples, Apex interfaces are utilized to express the dependencies between various units of code that you want to test in isolation.
By leveraging the ability to have multiple implementations of a given interface, we can vary which implementation gets executed. We can execute the real implementation of a method (this is provided by the preceding classes) or test only the mock behavior of it, typically defined in the test itself. Thus, depending on the type of test being written – an integration test or a unit test – you then pass the appropriate implementation of the Car class.
To support this type of injection, the following three things must be changed:
- Firstly, interfaces are created to reflect the methods on the Engine, Dashboard, and Display classes. The following code shows how these interfaces are defined:
public interface IEngine { void start(); void stop(); Boolean isRunning(); } public interface IDashboard { void initialise(); void updateRPMs(Integer rpms); void off(); } public interface IDisplay { void backlight(Boolean onOff); void showMessage(
Integer positionX, Integer positionY, String message); String getMessageShowAt(
Integer positionX, Integer positionY); Boolean isVisible(); }
- Secondly, the real implementation of the classes must implement the interfaces, since the interfaces are based on their methods. This typically just requires stating that the class implements the interface:
public class Engine implements IEngine { public class Dashboard implements IDashboard { public class Display implements IDisplay {
- Finally, references to the interface types, and not the concrete classes, must be made throughout the code base. For example, the Car constructor now takes the interface types, as do the engine and dashboard member types, used to call the methods:
public class Car { private IEngine engine; private IDashboard dashboard; private Boolean isRunning; public Car(IEngine engine, IDashboard dashboard) { this.dashboard = dashboard; this.engine = engine; }