Software Engineering for Self-Directed Learners »

Quality Assurance → Testing →

Dependency injection

What

Can explain dependency injection

Dependency injection is the process of 'injecting' objects to replace current dependencies with a different object. This is often used to inject stubs to isolate the from its so that it can be tested in isolation.

A Foo object normally depends on a Bar object, but you can inject a BarStub object so that the Foo object no longer depends on a Bar object. Now you can test the Foo object in isolation from the Bar object.


How

Can use dependency injection

Polymorphism can be used to implement dependency injection, as can be seen in the example given in [Quality Assurance → Testing → Unit Testing → Stubs] where a stub is injected to replace a dependency.

Here is another example of using polymorphism to implement dependency injection:

Suppose you want to unit test Payroll#totalSalary() given below. The method depends on the SalaryManager object to calculate the return value. Note how the setSalaryManager(SalaryManager) can be used to inject a SalaryManager object to replace the current SalaryManager object.

class Payroll {
    private SalaryManager manager = new SalaryManager();
    private String[] employees;

    void setEmployees(String[] employees) {
        this.employees = employees;
    }

    void setSalaryManager(SalaryManager sm) {
        this.manager = sm;
    }

    double totalSalary() {
        double total = 0;
        for (int i = 0; i < employees.length; i++) {
            total += manager.getSalaryForEmployee(employees[i]);
        }
        return total;
    }
}


class SalaryManager {
    double getSalaryForEmployee(String empID) {
        // code to access employee’s salary history
        // code to calculate total salary paid and return it
    }
}

During testing, you can inject a SalaryManagerStub object to replace the SalaryManager object.

class PayrollTest {
    public static void main(String[] args) {
        // test setup
        Payroll p = new Payroll();
        // dependency injection
        p.setSalaryManager(new SalaryManagerStub());
        // test case 1
        p.setEmployees(new String[]{"E001", "E002"});
        assertEquals(2500.0, p.totalSalary());
        // test case 2
        p.setEmployees(new String[]{"E001"});
        assertEquals(1000.0, p.totalSalary());
        // more tests ...
    }
}


class SalaryManagerStub extends SalaryManager {
    /** Returns hard coded values used for testing */
    double getSalaryForEmployee(String empID) {
        if (empID.equals("E001")) {
            return 1000.0;
        } else if (empID.equals("E002")) {
            return 1500.0;
        } else {
            throw new Error("unknown id");
        }
    }
}

Exercises