mockito_Mockito:无法实例化@InjectMocks字段:类型是接口

本文详细介绍了在使用Mockito进行测试时遇到的‘无法实例化@InjectMocks字段,类型是接口’的错误。问题源于尝试在接口上使用@InjectMocks注解,Mockito需要具体的实现类才能实例化。解决方案包括明确指定字段的实现类型或在初始化时提供具体类型。文章还探讨了如果受测类依赖于构造函数参数的情况,并提供了相应的解决建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mockito

mockito

使用Mockito进行Java类的模拟和存根的任何人,可能都熟悉InjectMocks -annotation。 在要测试上使用此批注,Mockito将尝试通过构造函数注入,setter注入或属性注入来注入模拟。 该魔术成功,无提示失败或抛出MockitoException

我想解释什么原因导致“ MockitoException:无法实例化名为xxx的@InjectMocks字段! 原因:类型是接口”以及解决方法。

问题

考虑以下JUnit 5测试,该测试可以验证女服务员是否可以正确提供早餐。 厨房工作人员中的任何人都可以提供早餐,并且该测试会验证当提供早餐时,咖啡机开始冲泡咖啡,而烤面包机开始烘烤。

 @ExtendWith (MockitoExtension. class )
 public class WaitressTest { 
  @Mock

  CoffeeMachine coffeeMachine;

  @Mock

  Toaster toaster;

  @InjectMocks

  KitchenStaff waitress;

  @Test

  void should_serve_breakfast() { 
    waitress.serve(BREAKFAST);

    verify(coffeeMachine).brew();

    verify(toaster).toast();

  }
 }
 interface KitchenStaff {

  void serve(MealType mealType);
 }
 Waitress class implements KitchenStaff { 
  CoffeeMachine coffeeMachine;

  Toaster toaster;

  //...

  @Override

  public void serve(MealType mealType) {

    coffeeMachine.brew();

    toaster.toast();

  }
 }

为了测试的目的,Mockito模拟了协作的coffeeMachinetoaster -因此它们需要Mock注释-这样我们就可以验证是否调用了预期的方法。 女服务员是真的,她正在接受测试。 通过在她身上放置@InjectMocks ,Mockito创建一个实例并传入两个协作者-然后调用我们实际的@Test -annotated方法。

不幸的是,它失败了:一旦运行测试,Mockito就会引发运行时异常: “无法实例化名为'waitress'的@InjectMocks字段! 原因:“ KitchenStaff”类型是接口。”

原因

幸运的是,最近Mockito的错误消息已得到改进,并且清楚地指出了问题所在: KitchenStaff类型是一种接口。

  1. 我们有一个界面。
     interface KitchenStaff {
    
      void serve(MealType mealType);
     }
    
  2. 我们对Mockito说:“实例化此接口”(什么?)
     @InjectMocks
     KitchenStaff waitress
    
  3. 嘿,那不对!

您不能仅在接口上使用@InjectMocks ,因为Mockito需要知道要实例化的具体类

请记住,您正在测试的单元是通常是真实的少数幸运之一。 KitchenStaff只是一个行为合同, Waitress实际上是得到报酬以提供早餐。

与使用抽象类一样,也有一些,但是归结为:在实例声明时提供具体的类型。

为Mockito提供实现该接口的类。

A)声明一个具体的类型

@InjectMocks字段的类型使用具体的实现。

 @InjectMocks
 Waitress waitress;

B)分配具体类型

继续对@InjectMocks字段使用接口的类型,但是使用具体的实现对其进行初始化。

 @InjectMocks
 KitchenStaff waitress = new Waitress()

或者当然在声明和初始化中使用具体类型,当然也可以

然而…

但是,您的受测类是否期望(必需)协作者作为构造函数的参数?(我当然希望如此!)

例如,考虑以下单个构造函数:

 Waitress class implements KitchenStaff { 
  final CoffeeMachine coffeeMachine;

  final Toaster toaster; 
  Waitress(CoffeeMachine coffeeMachine, Toaster toaster) {

    this .coffeeMachine = coffeeMachine;

    this .toaster = toaster;

  }

然后,在没有一个无参数的构造函数,编译器会告诉你调用适当的构造函数,并提供论据就在那里,现在

 @InjectMocks
 KitchenStaff waitress = new Waitress()

                                    ^^

                               compiler error

A.通过自己提供参数来解决。

 // compiles again
 @InjectMocks
 KitchenStaff waitress = new Waitress(coffeeMachine, toaster);

B.删除@InjectMocks您不再需要它

 KitchenStaff waitress;
 @BeforeEach
 void setup() {

  waitress = new Waitress(coffeeMachine, toaster);
 }

结论

相信女服务员为您做些美味的面包。

翻译自: https://www.javacodegeeks.com/2020/07/mockito-cannot-instantiate-injectmocks-field-the-type-is-an-interface.html

mockito

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值