【问题标题】:Mocking an abstract class with a mocked constructor argument?用模拟的构造函数参数模拟抽象类?
【发布时间】:2012-04-28 06:34:22
【问题描述】:

我想使用 Mockito 来对抽象类进行单元测试,详见 great answer.

诀窍在于,抽象类依赖于注入其构造函数的策略。我已经创建了该策略的模拟,我希望我的 BaseClass 模拟实例将模拟策略用于我的单元测试。

关于如何连接它有什么建议吗?我目前没有使用任何 IoC 框架,但正在考虑使用 Spring。也许它可以解决问题?

// abstract class to be tested w/ mock instance
abstract BaseClass
{
    // Strategy gets mocked too 
    protected BaseClass( Strategy strategy)
    {
        ...
    }
}

更新
根据 Mockito 邮件列表,目前没有办法将参数传递给模拟的构造函数。

【问题讨论】:

    标签: java spring unit-testing mocking mockito


    【解决方案1】:

    我最终只是使用反射在我的基类中设置了一个私有字段,如下所示:

    // mock the strategy dependency
    Strategy strategyMock = mock( Strategy.class);
    when(....).thenReturn(...);
    
    // mock the abstract base class
    BaseClass baseMock = mock(BaseClass.class, CALLS_REAL_METHODS);
    
    // get the private streategy field
    Field strategyField = baseMock.getClass().getSuperclass().getDeclaredField("_privateStrategy");
    
    // make remove final modifier and make field accessible
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(strategyField, strategyField.getModifiers() & ~Modifier.FINAL);          
    strategyField.setAccessible(true);
    
    // set the strategy
    strategyField.set(baseMock, strategyMock);
    
    // do unit tests with baseMock
    ...
    

    如果私有字段的名称发生变化,它会中断,但它会被注释掉,我可以忍受。很简单,只需要一行代码,我发现这比公开任何 setter 或必须在我的测试中显式继承子类更可取。

    编辑:所以它不再是一行代码,因为我的私有字段需要是“最终的”,需要一些额外的反射代码来解决。

    【讨论】:

    • 好帖子!如果你有一个 Spring 依赖项,你可以用一行来完成所有这些;-)。在窥探 Spring 的糖果盒时发现了这门课。 org.springframework.test.util.ReflectionTestUtils.setField(baseMock, "_privateStrategy", strategyMock)
    【解决方案2】:

    我已经看到在 Spring 上下文级别使用 Mockito 完成了这种事情。

    例如:

    <bean id="myStrategy" name="myStrategy" class="org.mockito.Mockito" factory-method="mock">
        <constructor-arg value="Strategy" />
    </bean>
    

    我希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      你不需要做任何特别的事情。像平常一样模拟 bean:

      Bean bean = mock(Bean.class); 
      when(bean.process()).thenReturn(somethingThatShouldBeNamedVO);
      

      正常工作:)

      【讨论】:

      • 谢谢,乔丹!不幸的是,我认为它不适用于我的情况,因为我需要在注入基础的策略类中进行特定的模拟行为。如果使用策略的默认模拟(仅返回 null、0 等),则模拟的 BaseClass 的逻辑将中断。不过谢谢!
      • 这没有回答问题。
      猜你喜欢
      • 2018-02-27
      • 1970-01-01
      • 1970-01-01
      • 2011-01-04
      • 1970-01-01
      • 2017-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多