【问题标题】:Mockito can't inject mocksMockito 无法注入模拟
【发布时间】:2019-07-08 18:29:50
【问题描述】:

我正在使用 Mockito,我正在尝试将 Mock CustomFileHandler 注入我的 REjercicioDAO 类以进行测试。问题是,我的测试没有抛出异常,但它没有注入我的模拟对象,原始的 @Autowired CustomFileHandler 没有被替换。这是我的代码:

@Repository
public class REjercicioDAO extends ARHibernateDAO < REjercicio > implements IREjercicioDAO {

    @Autowired
    public ICustomFileHandler customFileHandler;

    ...

}

这是我的测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ATest.CONTEXT_CONFIGURATION)
public class REjercicioDAOTest extends ATest {

    @Mock private ICustomFileHandler customFileHandler;

    @Autowired
    @InjectMocks
    private IREjercicioDAO rEjercicioDAO;

    @Before
    public void before () {

        MockitoAnnotations.initMocks(this);

        ...

    }

顺便说一句,实体按预期工作,接口正确链接到实际实体,我已经测试过了。我该如何解决这个问题?

【问题讨论】:

  • 猜测:测试代码中的自动装配注释......尝试删除那个。我相当怀疑将两个这样的注释放在同一个字段上会有什么好处。

标签: java spring mocking mockito integration-testing


【解决方案1】:

这里没有答案。我不能提供更多,因为我很遗憾看到这么多人使用这个依赖反射的笨拙 API,而您可以通过显式设置依赖项为类的读者做一些非常清楚的事情。

问题是,我的测试没有抛出异常,但它不会注入我的 模拟对象

不足为奇。即使没有注入成功,这种注入模拟的方式也会保持安静。 From the InjectMocks javadoc(重点不是我的!):

Mockito 将尝试仅通过构造函数注入来注入模拟, setter 注入,或按顺序和描述的属性注入 以下。如果以下任何策略失败,则 Mockito 不会 报告失败; 即您必须自己提供依赖项。

虽然 Mockito 不报告失败,但我真的不鼓励使用此 API。

关于您的实际问题,请看:

@Autowired
@InjectMocks
private IREjercicioDAO rEjercicioDAO;

您使用 Spring 和 Mockito 注释对字段进行注释。您对他们的处理顺序感到满意吗?这些来自两个不同的库。我不会说它永远不会起作用(运气和随机存在),但你真的认为它很健壮吗?

为了满足您的要求,您可以编写类似的东西,分两个明确的步骤来完成:
- 对象实例化:模拟依赖并注入 spring 依赖
- 关系集:mock 依赖和 spring 依赖之间

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ATest.CONTEXT_CONFIGURATION)
public class REjercicioDAOTest extends ATest {

    @Mock 
    private ICustomFileHandler customFileHandler;

    @Autowired        
    private IREjercicioDAO rEjercicioDAO;

    @Before
    public void before () {    
        MockitoAnnotations.initMocks(this);
        // Set explicitly the fileHandler dependency
        rEjercicioDAO.setFileHandler(customFileHandler);         
    }
 }

【讨论】:

  • 谢谢,我想我只需要使用一个setter作为依赖,因为它比处理库配置和集成更容易
  • 不:感谢您改变方法!更简单也更清晰!
【解决方案2】:

您正在尝试将 IT 与单元测试混合使用。

1)如果您使用的是 Spring Boot:

@MockBean
private ICustomFileHandler customFileHandler;

@Autowired
private IREjercicioDAO rEjercicioDAO;

就是这样..

2) 不使用 Spring Boot:

public class TestConfig{

    @Bean
    @Primary
    public ICustomFileHandler customFileHandler(){
       return Mockito.mock(ICustomFileHandler.class);
    }

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ATest.CONTEXT_CONFIGURATION, classes=TestConfig.class)
public class REjercicioDAOTest extends ATest {

   @Autowired
   private ICustomFileHandler customFileHandlerMock; 

    @Autowired
    private IREjercicioDAO rEjercicioDAO;

模拟被注入,您可以根据需要在测试中设置它

【讨论】:

  • 感谢您的回答,但是,您的意思是我将 IT 和单元混合在一起是什么意思?我正在尝试对 REjercicioDAO 进行单元测试,这就是我尝试模拟依赖项的原因,因此我可以在隔离其他外部实体的情况下测试这些方法
  • 您不会自动装配并在单元测试中启动上下文;)
  • 我想我没听懂。如果我要测试的是自动装配的类,为什么我不想自动装配,我需要一个实体来执行测试?
  • 也许你真的需要一个单元测试..但在这种情况下你不需要像 SpringJUnit4ClassRunner 和 Autowiring 这样的东西..你在单元测试中不需要任何特定于框架的东西
  • 对不起,如果我是笨蛋,我对测试有点陌生,但我是否仍然“需要”模拟实体?我需要一些方法来确保我的代码中的依赖项返回一些已知值,以便我可以单独测试其余代码。如果是这样的话,那么我需要一个像 mockito 这样的框架,或者自己制作模拟类,但我读过这不是一个好主意
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 2017-10-11
  • 1970-01-01
相关资源
最近更新 更多