Mockito测试类,在构造函数中创建依赖项

时间:2017-08-08 09:59:37

标签: java unit-testing junit mockito

我正在尝试为遗留代码编写一个如下所示的测试:

public class TestedClass {
    private A a = StaticFactory.createA();
    private B b = StaticFactory.createB();
    // No default constructor
    // code using A and B classes
}

就我对Mockito的理解而言,我知道我不能模拟静态方法,但是我知道我可以使用一个小技巧并将这个对象的创建外部化为这样的包私有方法:

public class TestedClass {

    private A a;
    private B b;

    TestedClass() {
        a = createA();
        b = createB();
    }

    A createA() {
        return StaticFactory.createA();
    }

    B createB() {
        return StaticFactory.createB();
    }

    // code using A and B classes
}

但是使用这种结构我无法创建TestedClass的间谍,它必须已经是使用doReturn(..)构造的间谍,所以这样的测试不会起作用:

public class TestedClassTest {

    TestedClass testedClass;

    A mockA;
    B mockB;

    @Before
    public void setUp() {
        mockA = mock(A.class);
        mockB = mock(B.class);

        testedClass = Mockito.spy(new TestedClass());

        doReturn(mockA).when(testedClass).createA();
        doReturn(mockB).when(testedClass).createB();   
    }
}

是否有其他方法可以更改在构造函数中被触发的createAcreateB方法的行为,以确保我有模拟实例?

在这种情况下,StaticFactory.createA()运行并抛出异常(仅在测试中),使我无法完成测试的初始化。

Running pl.tbawor.TestedClassTest
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.168 sec <<< FAILURE!
shouldTestSomething(pl.tbawor.TestedClassTest)  Time elapsed: 0.114 sec  <<< ERROR!
java.lang.NullPointerException
        at pl.tbawor.StaticFactory.createA(TestedClass.java:32)
        at pl.tbawor.TestedClass.createA(TestedClass.java:14)
        at pl.tbawor.TestedClass.<init>(TestedClass.java:9)
        at pl.tbawor.TestedClassTest.setUp(TestedClassTest.java:26)

我的目标是避免为创建AB对象运行原始方法,以防止抛出异常。

此外,由于这是遗留项目,我无法添加任何其他库(PowerMock)。

我将补充说,TestingClass修改应该尽可能少。

1 个答案:

答案 0 :(得分:5)

您必须在间谍实例上记录行为,但是在创建间谍之前就这样做了。

这里:

doReturn(mockA).when(testedClass).createA();
doReturn(mockB).when(testedClass).createB();
testedClass = Mockito.spy(new TestedClass());
当您记录模拟行为时,

testedClassnull

颠倒这些陈述的顺序:

testedClass = Mockito.spy(new TestedClass());
doReturn(mockA).when(testedClass).createA();
doReturn(mockB).when(testedClass).createB();

此外,此解决方案无法解决您的根问题,因为调用的no-arg构造函数仍然依赖于您要隔离的依赖项,但目前还没有:

TestedClass() {
    a = createA();
    b = createB();
}

你应该重构一点TestedClass以允许设置依赖关系 例如,您可以重载构造函数:

TestedClass(A a, B b) {
    this.a = a;
    this.b = b;
}

通过这种方式,您可以模拟TestedClass的依赖关系:

@Before
public void setUp() {
    mockA = Mockito.mock(A.class);
    mockB = Mockito.mock(B.class);
    testedClass = new TestedClass(mockA, mockB);
}