How to Refactor for Testability

To test save() in isolation, you must apply Dependency Injection (DI).

Instead of creating the Database inside the class, you inject it via the constructor. This allows you to pass a "Mock" database during testing.

transform The Refactoring Process

warning TIGHT COUPLING

The "New" Operator is the Enemy

Your original code instantiates new Database() directly inside the method.

This creates a hard dependency. When you try to write a unit test, your code will try to connect to a real database. You cannot stop it, intercept it, or mock it.

// Original Code
class PersonController 
{
    public void save(Person person) 
    {
        // PROBLEM:
        new Database().save(person);
    }
}
// Step 1: Define Interface
// 1. Create an interface (Contract)
interface IDatabase 
{
    void save(Person person);
}

class RealDatabase implements IDatabase 
{
    public void save(Person p) { ... }
}
// Step 2: Constructor Injection
class PersonController 
{
    private final IDatabase database;

    // Inject dependency via constructor
    public PersonController(IDatabase db) 
    {
        this.database = db;
    }

    public void save(Person person) 
    {
        // Use the injected instance
        this.database.save(person);
    }
}
// The Unit Test
class PersonControllerTest 
{
    @Test
    public void testSaveInIsolation() 
    {
        // 1. Arrange: Create Mock
        MockDatabase mockDb = new MockDatabase();
        PersonController ctrl = new PersonController(mockDb);
        Person p = new Person("John");

        // 2. Act
        ctrl.save(p);

        // 3. Assert: Verify mock was called
        assertTrue(mockDb.wasSaveCalled);
    }
}

science Interactive Test Simulator

Assemble your components and run the test to see Dependency Injection in action.

Class Under Test
settings

PersonController

Constructor needs: IDatabase
Select Dependency to Inject:
> Waiting for setup...

code Complete Refactored Class

public class PersonController {
    
    private final IDatabase database;

    // Constructor Injection
    public PersonController(IDatabase database) {
        this.database = database;
    }

    public void save(Person person) {
        this.database.save(person);
    }
}

science Complete Unit Test

public class PersonControllerTest {
    
    public void testSave() {
        // 1. Mock
        MockDatabase mock = new MockDatabase();
        
        // 2. Inject Mock
        PersonController ctrl = new PersonController(mock);
        
        // 3. Run & Verify
        ctrl.save(new Person("Alice"));
        assert(mock.savedPerson != null);
    }
}