Mockito模拟对象返回null

32

我尝试为我的JSF应用程序实现一些测试,并使用mockito进行模拟。 (我也使用spring)

@RunWith(MockitoJUnitRunner.class)
public class GeneralConfigServiceImplTest  {

    private GeneralConfigService generalConfigService;

    @Mock
    private GeneralConfigDAO generalConfigDAO;

    @Mock
    private GeneralConfig gen;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        generalConfigService = new GeneralConfigService();
        ReflectionTestUtils.setField(generalConfigService, "generalConfigDAO", generalConfigDAO);                  
    }

    @Test
    public void testAddGeneralConfigCallDAOSuccess() throws DAOException, EntityNullException, IllegalEntityArgumentException, ParseException, EntityPersistException {
        gen = createGeneralConfigs("label", "value");

        generalConfigService.setInstance(gen);
        generalConfigService.persist();
        log.info(generalConfigService.getInstance().toString());
    }
}
测试成功,但是当我想使用getInstance方法检索实例时,我之前通过构造函数设置的所有参数都为null。我对模拟对象很陌生,请问这种行为是正常的,还是我的代码有问题?

这似乎与模拟无关,因为您没有模拟相关对象。 - Duncan Jones
5个回答

23

这很大程度上取决于GeneralConfigService#getInstance()的实现。如果您使用@InjectMocks注释,还可以大大简化测试代码。

使用MockitoJUnitRunner时,无需手动初始化模拟对象和注入依赖项:

@RunWith(MockitoJUnitRunner.class)
public class GeneralConfigServiceImplTest  {

    @InjectMocks
    private GeneralConfigService generalConfigService;

    @Mock
    private GeneralConfigDAO generalConfigDAO;

    @Test
    public void testAddGeneralConfigCallDAOSuccess() {
       // generalConfigService is already instantiated and populated with dependencies here
       ...
    }
}

2
这里放一个链接:https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/ - Lars Bohl
我遇到了这个错误 - java.lang.AbstractMethodError: org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.isTypeMockable(Ljava/lang/Class;)Lorg/mockito/plugins/MockMaker$TypeMockability - Jay Modi

14

我的问题在于Test注释的错误导入:

错误导入:

import org.junit.jupiter.api.Test;

正确导入:

import org.junit.Test;


你使用的是哪个版本? - Andoy Abarquez
@Andrew 4.x吧,现在没有代码访问权限。 - FabianoLothor

12

别忘了使用

MockitoAnnotations.initMocks(this);
如果您正在使用注释来模拟对象,即 @Mock Objectname

4
使用Mockito JUnit运行器时,不需要使用initMocks。 - Bradley M Handy
今天我在主类中使用模拟。耶~ - Tiina
在JUnit中确实不需要这个语句。但是那天我在一个不是JUnit方法的主方法中运行它,你的答案帮了我大忙 :) - Tiina
很酷,听起来不错 :) - Swarit Agarwal
MockitoAnnotations.initMocks(this)已经过时。 - Shoniisra

8

Mockito框架中的所有方法调用默认返回null。如果你希望它返回其他内容,需要通过when语句告诉它如何做。

看起来你认为以下代码会起作用...你调用setInstance然后期望getInstance返回传递给setInstance的值,因为这是DAO的工作原理。如果这是你尝试的内容,那么你不应该通过调用getInstance来测试setInstance,因为getInstance将返回你配置模拟对象返回的任何内容,而与传递给setInstance的值没有关系。相反,使用verify来验证从setInstance方法调用的DAO的适当方法。

例如,如果GeneralConfigService.setInstance调用GeneralConfigDAO.setInstance,那么你的测试应该像这样...

@Test
public void testAddGeneralConfigCallDAOSuccess() throws DAOException, EntityNullException, IllegalEntityArgumentException, ParseException, EntityPersistException {
    gen = createGeneralConfigs("label", "value");

    generalConfigService.setInstance(gen);
    generalConfigService.persist();

    verify(genConfigDAO).setInstance(sameInstance(gen));
}

此外,如果gen是一个模拟对象(通过@Mock),为什么要通过gen = createGeneralConfigs...将其赋值给其他变量呢?

1

这个帖子早已过时,但是我遇到了与junit5(v5.8.2)和mockito(mockito-core:jar:4.5.1)相关的同样问题,这里的任何答案都没有帮到我。经过1.5小时的搜索,我找到了这篇文章:

https://mincong.io/2020/04/19/mockito-junit5/

这对我很有帮助!我使用了第一个解决方案,所以我添加了

    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-junit-jupiter</artifactId>
        <version>2.28.2</version>
        <scope>test</scope>
    </dependency>

我新增了一个依赖,并在我的类上注释了以下注解(并移除@RunWith(MockitoJUnitRunner.class) 注解):
@ExtendWith(MockitoExtension.class)

请在文章中找到解释。我希望这也能帮助其他人!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接