【问题标题】:Junit 4 scope of @Mock in @Produces methods@Produces 方法中 @Mock 的 Junit 4 范围
【发布时间】:2019-09-07 07:26:22
【问题描述】:

如果使用注释 @Mock 进行模拟,为什么模拟对象在测试类实例化后显示为“锁定”并且在 @Produced 方法中显示为 null

public class MyTest {

   @Rule
   public MockitoRule rule = MockitoJUnit.rule();

   @Rule
   public WeldInitiator weld = WeldInitiator.from(MyTest.class).build();

   //@Mock <-- this wont work. Will be null in the @Produces methods
   private ClassThatSutInjects sutInject= mock(ClassThatSutInjects.class);

   private NeedsTest sut;

   @Before
   public void setup() {
      sut = weld.select(NeedsTest.class).get();
   }

   @Test
   public void doesThisWork() {
      //Arrange
      //Mockito.when(sutInject.multiply(anyInt()))
      // .thenReturn(3);//this has no effect on the mock returned by @Produces

      //Act
      sut.doThis(1234);

      //Assert

  }

  @Produces
  public ClassThatSutInjects mockThatClass() {
      Mockito.when(sutInject.multiply(anyInt())).thenReturn(100);   //<-- this works
      return sutInject;
  }

}

public class NeedsTest {
   @Inject
   ClassThatSutInjects someClass

   public void doThis(int number) {
      return someClass.multiply(number);
   }

}

有两件事让我感到困惑,我希望得到一些帮助来理解:

1) @Mock(带注释的字段)在 @Producer 方法中为空,但如果我使用 = Mockito.mock(xxx.class) 代替,则初始化。据我所知,这与何时执行符号与何时应用 @Rule 有关。更多细节将不胜感激......

2) 我非常希望能够让 mock 在不同的测试用例中做不同的事情,但这似乎是不可能的,因为当 mockito.when() 没有时 @Produces 方法“停留在过去”还没申请。我怎样才能“安排”公关。测试用例?拥有一个测试级公关。随着时间的推移,测试用例将变得无法维护......代码变得非常混乱。

编辑:我发现将我的模拟对象设为静态,可以设置我的模拟对象 pr。测试方法。我进行了调试运行,并注意到生产者返回的对象与 jUnit @Test 中使用的实例不同 - 显然 @Produces 在 MyTest 类的另一个实例上运行......对我来说仍然没有意义,还是这样:如果有人有一些知识,请分享。

【问题讨论】:

  • 您打算编写IntegrationTest 还是UnitTest?其次,您根本不需要使用 CDI,可以直接提供模拟。 “卡在过去”背后的问题可能是焊缝可能会将模拟包装成代理。
  • 我的意图是编写一个集成测试,但在 jUnit 设置中运行它以避免启动容器。我已经对帖子进行了更新。我做了一些调试,因为我记得你提到的关于代理的事情。
  • 也许 cdi-unit 或 ioc-unit (github.com/1and1/ioc-unit/tree/master/ioc-unit-mockseasy) 对您的情况有所帮助。要使“@Mock”有效,Mockito 必须了解该类。要使“@Inject”生效,如果“@InjectMocks”不够,则必须运行 CDI。

标签: java mockito junit4 weld


【解决方案1】:

正如您已经观察到的,生产者在对象的不同实例上运行。

Source(第 8.1 章生产者方法的范围):

生产者方法不继承声明该​​方法的 bean 的范围。这里有两种不同的bean:生产者方法和声明它的bean。生产者方法的范围决定了该方法被调用的频率,以及该方法返回的对象的生命周期。声明 producer 方法的 bean 的范围决定了调用 producer 方法的对象的生命周期。

使字段静态可以解决这个问题,但这并不是一个很好的解决方案。

【讨论】:

  • 我同意静态不好(从来都不是)。任何关于其他解决方案的建议将不胜感激。我想也许将生产者移动到一个单独的类并通过 Weld 访问它以编辑“测试行为”
  • 为什么在集成测试中需要CDI?在注入某些类后,可以选择用模拟替换它们,但是你可以再次设置对象而不使用CDI,你的spin up the container 做了什么,你不想手动操作?
  • 另一个选项可能不是注入模拟,而是注入stubs,它允许您通过设置方法定义它们的行为(然后您可以在其中设置模拟)。这将要求您使用并希望替换的每个注入类都具有适当的接口。
  • 我在集成测试中需要 CDI 的原因是因为被测类使用注入 :) 我所说的不“启动容器”的意思是基本上我不想测试依赖于外部服务的答案。我不想模拟我的外部依赖项,它们是通过注入提供的。
猜你喜欢
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
相关资源
最近更新 更多