如何只模拟一个注入依赖项的一个方法并正常注入其余的方法?

时间:2017-09-06 13:20:29

标签: java unit-testing dependency-injection mocking mockito

我正在为一个大量使用依赖注入的项目编写测试。

通常我只会注入我正在测试的对象:

public class RegistrationTest
        extends WithApplication {

    private RegistrationController controller;

    @Before
    public void setUp() throws Exception {
        Injector injector = app.injector();
        controller = injector.instanceOf(RegistrationController.class);
    }

    @Test
    public void openRegistrationView() {
        Result result = controller.registrationForm();
        assertEquals(OK, result.status());
    }
}

现在我需要模拟一个被测试类的依赖关系的方法的返回值。

为此,我可以使用@InjectMocks@RunWith(MockitoJUnitRunner.class)注入模拟的依赖项。

@RunWith(MockitoJUnitRunner.class)
public class RegistrationTest
        extends WithApplication {

    @InjectMocks
    private RegistrationController controller;
    @Mock
    private FormFactory formFactory;
    @Mock
    private RegistrationIpCache registrationIpCache;

    @Test
    public void openRegistrationView() {
        doReturn("test").when(registrationIpCache).getLast();
        Result result = controller.registrationForm();
        assertEquals(OK, result.status());
    }
}

但是我只想模拟RegistrationIpCache的一个方法调用,我需要模拟整个类,并且我需要在我的示例中模拟RegistrationController的所有其他依赖项,如FormFactory 。现在,所有模拟类的每个方法都没有按预期工作。

当然,我可以使用doCallRealMethod()来模拟所有依赖项的每个方法

doCallRealMethod().when(formFactory).form(Registration.class);

但正如您已经可以想象的那样,工作所需的样板代码量是极端的。

是否可以正常注入我的课程,然后只监视一个依赖项或模拟一个依赖项的一个方法?

1 个答案:

答案 0 :(得分:3)

您需要使用@Spy而不是@Mock

@InjectMocks
private RegistrationController controller;
@Mock
private FormFactory formFactory;
@Spy
private RegistrationIpCache registrationIpCache;

但请注意,在这种情况下@Spy将尝试使用默认构造函数。 如果默认构造函数不可用,请使用显式构造函数调用:

@Spy
private RegistrationIpCache registrationIpCache = new RegistrationIpCache(dependencies);

以下是Mockito无法从@Spy javadoc实例化您的课程的情况:

  

Mockito将尝试找到零参数构造函数(甚至私有)和   为你创建一个实例。但是Mockito无法实例化内心   类,本地类,抽象类和接口。

以下是手动注入依赖项的示例:

@RunWith(MockitoJUnitRunner.class)
public class RegistrationTest {
    private RegistrationController controller;

    private RegistrationIpCache spyRegistrationIpCache; //this is the dependencies that you need to spy

    @Before
    public void setUp() throws Exception {
        spyRegistrationIpCache = spy(realInstanceOfregistrationIpCache);

        controller = new RegistrationController(registrationIpCache, realInstanceOfFormFactory);
    }
}

在这种情况下,您需要编写更多代码,但这使您可以更好地控制对象实例化和依赖项注入。 请注意,不需要使用构造函数实例化。由于您手动执行此操作,因此可以根据需要对其进行实例化。