injectmocks_@InjectMocks的危险

injectmocks

上周,我写了有关初始化Mockito模拟和我个人喜好的方法。 我仍在从事旧项目,我想更深入地了解所使用的Mockito的某些功能。

例如,Mockito的开发人员在设计上采取了强烈的自决立场:Mockito只能模拟公共非最终实例方法。 我完全赞同这一点。 要超出此范围,您必须使用PowerMock (我之前写过 )。 很好,因为对我而言,在类路径上发现PowerMock是代码气味的确定标志。 您正在使用的库需要进行一些设计上的改进...或者绝对可以编写代码。

但是,我认为Mockito在其API中有些类似于PowerMock的危险功能。 这样的功能之一就是能够通过反射注入依赖项的依赖项。 不清楚吗 让我们来看一个具有以下类层次结构的示例:

示例类图

单元测试的规则要求在测试ToTest ,我们将模拟依赖项DepADepB 。 让我们进一步扩展示例, DepADepB是以下类:

  • 由于它们来自第三方库/框架,因此超出了我们的能力范围
  • 以难以模拟的方式进行设计, 它们需要大量的模拟行为

在这种情况下,我们将不会仅对我们的类进行单元测试,而是对ToTestDepADepB的行为进行集成测试。 由于上述局限性,这不是圣杯,而是可以接受的。

现在让我们DepA一件事: DepADepB本身依赖于其他类。 而且由于设计@Autowiring ,它们依赖于通过@Autowiring进行字段注入-没有构造函数甚至setter注入都可用。 在这种情况下,必须通过Java API或诸如Spring的ReflectionTestUtils类的实用程序类,使用反射来设置那些依赖项。 在这两种情况下,这都是非常脆弱的,因为它基于属性的名称:

DepAdepA=newDepA();
DepXdepX=newDepX();
DepYdepY=newDepY();

ReflectionTestUtils.setField(depA,"depX",depX);
ReflectionTestUtils.setField(depA,"depY",depY);

提供的Mockito一个简单的替代这个方法:使用@InjectMocks ,是的Mockito能够自动注入嘲笑依赖是在上下文中

@RunWith(MockitoJUnitRunner.class)
publicclassTest{

    @InjectMocksprivateDepAdepA=newDepA();
    @MockprivateDepXdepX;
    @MockprivateDepYdepY;
    // tests follow
}

由于depXdepY都嘲笑我的Mockito,他们是在上下文中,因此可以自动被注入depA通过的Mockito。 而且由于它们是模拟的,因此可以针对行为进行定位。

虽然有一些缺点。 最重要的是您松开了显式注入-也是我不使用自动装配的原因。 在这种情况下,您的IDE可能会将depXdepY报告为未使用。 更糟糕的是, DepA初始结构的DepA不会触发未使用字段的任何警告。 最后,作为反思,这些更改可能会导致运行时异常。

最重要的问题@InjectMocks ,但是,它的使用非常方便,太容易了...... @InjectMocks皮这两个领域注入和太多的依赖问题。 那些应该会受伤,但使用@InjectMocks时不再@InjectMocks 。 因此,如果将其应用于来自库的依赖项(如depAdepB ,则别无选择。 但是,如果您开始将其用于自己的类(也就是 ToTest ,那么这肯定看起来像是代码的味道。

翻译自: https://blog.frankel.ch/the-danger-of-injectmocks/

injectmocks

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值