Search code examples
javaunit-testingmockitodependencies

Java Unit Test Mock, target class new() method requires depencies mock


I want to test A class.

In A class constructor method, a private final dependency d is created. I want to mock d. Here is the code



public class A {
    public A () throws FileNotFoundException {}
    private final D d = new D();
}

public class D { 
    public D () throws FileNotFoundException {
        Reader reader = new InputStreamReader(new FileInputStream("filePath"));
        // other code...
    }
}

Since the filePath is a special path fitting in the docker config, me and my mentor decided to use MOCK to return a d to test A class.

I did not know how to mock this situation. Previously, I did use FieldSetter in Mockito to solve simple cases.


Solution

  • The first option would be to declare D as a constructor argument. This is also called dependency injection and can be useful for testing. Additionally, you can still have a constructor without any arguments:

    public class A {
        public A (D d) throws FileNotFoundException {
            this.d = d;
        }
        public A () throws FileNotFoundException {
            this(new D());
        }
    
        private final D d;
    } 
    
    @Test
    void test() {
        D mock = mock(D.class);
        A tested = new A(mock);
        // ...
    }
    

    Alternatively, you can test this code even more elegantly, without any mocks. To do so, we need to apply the same technique to D and use dependency injection for passing a Reader:

    public class D { 
        public D () throws FileNotFoundException {
            this(new InputStreamReader(new FileInputStream("filePath")));
        }
        public D (Reader reader) throws FileNotFoundException {
            // other code...
        }
    }
    

    Since Reader is an interface, we can use different implementations for it, inside the test. For instance, we can use a StringReader:

    @Test
    void test() {
        D d = new D(new StringReader("my test file content"));
        A tested = new A(d);
        // ...
    }