DEV Community

Discussion on: SOLID Principles for OOP

Collapse
 
zankyr profile image
zankyr

Let's say that you want to test that, by calling BrickLayer.ConstructHouse(), all the exceptions are handled correctly. Using DI allows you to inject a mocked object, configured to throw an exception when required:

// given
BrickLayer mockedBrickLayer = mock(BrickLayer.class);
when(mockedBrickLayer.ConstructHouse()).then(throw new Exception());

// then
assertThrow(new HouseBuilder().BuildHouse(mockedBrickLayer));
Enter fullscreen mode Exit fullscreen mode

In this test case you don't care how or why the exception is thrown (incorrect or missing data etc), you just care about how you're handling that exception. DI allows you to build tests without worrying about the logic within the dependencies (in our case, the BrickLayer).

Another example: what if the BrickLayer.ConstructHouse() bases its logic on external data? For example, data from a database or external API.

public class BrickLayer {

    public void ConstructHouse() {
        // retrieve data from the external
        var externalData = callTheExternalService();

        // do your magic
        if (extarnalData.something()) {
            Console.Writing(...);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Without a DI, in your tests you are strictly bound to the response provided by the external system. So, you really have to call the system, which means moving to integration or end-to-end testing.
Using the DI, you don't need a working external system, but you can easily simulate its behavior:

// given
BrickLayer mockedBrickLayer = mock(BrickLayer.class);
when(mockedBrickLayer.ConstructHouse()).then(Console.writing(...));

// when
new HouseBuilder().BuildHouse(mockedBrickLayer));

// then
assertEquals("The expected message", Console.ReadKey());
Enter fullscreen mode Exit fullscreen mode