【问题标题】:Mockito and CDI bean injection, does @InjectMocks call @PostConstruct?Mockito 和 CDI bean 注入,@InjectMocks 是否调用 @PostConstruct?
【发布时间】:2015-06-01 20:50:48
【问题描述】:

我有这个代码:

class Patient {

  @Inject Syringe syringe;

  @PostConstruct
  void sayThankyouDoc() {

    System.out.println("That hurt like crazy!");

  }

}

@RunWith(MockitoJUnitRunner.class)
class TestCase {

  @Mock
  Syringe siringeMock;

  @InjectMocks
  Patient patient;

  //...

}

我预计 Mockito 会调用 PostConstruct,但我必须添加:

@Before
public void simulate_post_construct() throws Exception {
    Method postConstruct = Patient.class.getDeclaredMethod("sayThankyouDoc", null);
    postConstruct.setAccessible(true);
    postConstruct.invoke(patient);
}

有没有更好的方法来做到这一点?

【问题讨论】:

  • 另一种更具可读性和更易于测试的设计是根本不使用@PostConstruct,而是使用构造函数注入而不是字段注入
  • @geoand 但是构造函数注入是什么?

标签: java junit mockito cdi postconstruct


【解决方案1】:

虽然不能直接回答您的问题,但我建议您放弃字段注入并改用构造函数注入(使代码更具可读性和可测试性)。

您的代码如下所示:

class Patient {

  private final Syringe syringe;

  @Inject
  public Patient(Syringe syringe) {
    System.out.println("That hurt like crazy!");
  }

}

那么你的测试就是:

@RunWith(MockitoJUnitRunner.class)
class TestCase {

  @Mock
  Syringe siringeMock;

  Patient patient;

  @Before
  public void setup() {
     patient = new Patient(siringeMock);
  }

}

更新

根据 cmets 中 Erik-Karl 的建议,您可以使用 @InjectMocks 摆脱设置方法。该解决方案有效,因为 Mockito 将使用适当的构造函数注入(如 here 所述)。 代码将如下所示:

@RunWith(MockitoJUnitRunner.class)
class TestCase {

  @Mock
  Syringe siringeMock;

  @InjectMocks
  Patient patient;

}

【讨论】:

  • 不仅更易于测试,而且通过将字段设置为最终字段,您可以获得一些线程安全保证。请注意,即使使用上述代码,您也需要手动调用 @PostConstruct 方法
  • 可能有点老了,但我只想补充:如果可用,InjectMock 将通过构造函数注入。所以在这里,您只需要使用 InjectMock 注释 Patient 并且可以摆脱 setup 方法。
  • @Eric-Karl 非常有用!谢谢!我用你的建议更新了答案
猜你喜欢
  • 2013-05-23
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-02
相关资源
最近更新 更多