使用MockitoJUnitRunner运行测试无法通过验证断言

时间:2020-05-31 03:18:54

标签: java spring-boot testing junit mockito

是否可以在类中没有@RunWith(MockitoJUnitRunner)注释的情况下模拟存储库?

我有一个测试通过了,没有注释,但是失败了。没有它,我的回购测试将无法进行。这是一个陷阱22。

当我使用该批注时,我的测试中的when()方法不再具有存根行为,模拟也不执行任何操作,并且尽管设置了断点并击中了这些断点(表明行/方法正在运行),verify(。 。,times(x))语句表示模拟对象从未与该方法进行交互。我一直在努力解释为什么使用@RunWith(MockitoJUnitRunner)注释会使Mockito的最简单部分无法正常工作。

我找不到任何询问此问题的主题,但也许有人知道可以使用更好的关键字。这听起来像一个已知问题吗?

这是我的考试:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;

// toggling this below annotation is the source of grief.
//@RunWith(MockitoJUnitRunner.class)
public class LoadEditEntityChangeLogServiceImplTest {

    @InjectMocks
    private ServiceImpl serviceMock;

    @Mock
    private EditStepRepository editStepRepository;

    @Mock
    private EditMapper editMapper;

    @Before
    public void init() {
        initMocks(this);
    }


    @Test // when the RunWith is commented out, this passes. When it is not, the test fails the verify assert. 
    public void mapEditEntityFromAction_Test() {
        EditDTO editDTO = Mockito.mock(EditDTO.class);
        when(editDTO.getSysNum()).thenReturn((long)7334);

        EditEntity editEntity = new editEntity();
        editEntity.setSysNum(editDTO.getSysNum());

        when(editMapper.mapToEntity(eq(editDTO))).thenReturn(editEntity);

        editEntity response = serviceMock.mapEditEntityFromAction(editDTO);

        verify(loadEditMapper, times(1)).mapToEntity(eq(loadEventDTO));
        assertEquals(loadEventDTO.getSystemNumber(), response.getSystemNumber());
    }

    @Test // this will fail without the @RunWith as the mocked repo will be null and throws NullPointerException when used.
    public void updateConvertedEventSegment_Test() {
        EditEntity editEntity = new EditEntity();
        EditStepEntity editStepEntity = new EditStepEntity();
        editEntity.setEditStep(editStepEntity);

        doReturn(editStepEntity).when(editStepRepository).save(any());

        serviceMock.updateEditStep(editEntity);

        verify(editEntity, times(1)).getEditStep();
        verify(editStepRepository, times(1)).save(eq(editStepEntity));
    }
}

1 个答案:

答案 0 :(得分:1)

您应该了解这位跑步者的实际行为:

基本上,它允许将模拟(由Mockito.mock(...)进行模拟准备)注入到用@Mock注释的测试字段中。在问题中,由于您已经注释掉了跑步者,所以所有这些字段都将为空。

当您用@InjectMocks进行注释时-它将把模拟注入到注释后引用类型的对象的字段中。

这里需要澄清的一点是:MockitoAnnotations.initMocks(this)与“运行程序”的作用相同,因此无需同时包含两者(如果出于某种原因不能使用运行程序,则应使用initMocks ,例如是否已经有另一个跑步者必须使用)

现在,您问:

是否可以在类中没有@RunWith(MockitoJUnitRunner)注释的情况下模拟存储库?

答案是-是的,您可以,实际上您不必使用流道,有时更方便。

因此,假设您确实使用了该运行器,那么真正的问题是“我的存储库不起作用”到底是什么意思。这是否意味着服务中存在指向该存储库及其空值的引用?

这是否意味着存在一个存储库模拟,但是当您执行“在测试中”调用时,模拟是不同的吗?

您没有在代码中显示它,但是我假设您有这样的东西:

public class ServiceImpl {
   private final EditStepRepository editStepRepository;

   public ServiceImpl(EditStepRepository editStepRepository) {
      this.editStepRepository = editStepRepository;
   }
   ...
}

但是,如果是这样,一旦创建了一个模拟(确实应该在ServiceImpl类中注入了模拟(使用调试器或其他工具进行检查),则应该在存储库中指定期望值,通常是在测试中应该是这样的代码:

Mockito.when(editStepRepository.doSomething(...)).thenReturn(...)

您没有放置任何这些行,所以它不起作用。

但是总的来说,由于这个问题包含许多不确定的技术因素,因此我只能说是推测...