【问题标题】:Injecting Mockito Mock objects using Spring JavaConfig and @Autowired使用 Spring JavaConfig 和 @Autowired 注入 Mockito Mock 对象
【发布时间】:2013-02-15 13:39:14
【问题描述】:

我正在尝试用 Mockito 模拟对象替换 @Autowired 对象。通常的做法是使用 Springockito 使用 xml:

<mockito:mock id="SomeMock" class="com.package.MockInterface" />

目前我正在尝试转而使用 Spring 的 JavaConfig 来完成这项工作。突然之间,Java 表达式比 xml 更加冗长:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MyTestClass {

    @Configuration
    static class Config {
        @Bean
        public MockInterface somethingSpecial() {
            return Mockito.mock(MockInterface.class);
        }
    }

    @Autowired MockInterface mockObj;

    // test code
}

我发现了一个名为 Springockito-annotations 的库,它允许您执行以下操作:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=SpringockitoContextLoader.class)
public class MyTestClass {

    @Autowired @ReplaceWithMock MockInterface mockObj;

    // test code
}

很明显,漂亮多了 :) 唯一的问题是这个上下文加载器不允许我将 @Configuration 和 JavaConfig 用于其他 bean(如果我这样做,Spring 会抱怨没有匹配那些自动装配的候选字段)。

你们知道让 Spring 的 JavaConfig 和 Springockito-annotations 发挥良好作用的方法吗?或者,是否有另一种创建模拟的简写?

作为一个不错的奖励,使用 Springockito 和 xml 配置,我能够模拟出具体的类,而无需为其依赖项提供自动装配候选者(如果有的话)。没有xml,这不可能吗?

【问题讨论】:

  • 也许我有点困惑,但你为什么不 @Autowired 你想要的应用程序上下文中的 bean 和 @Mock 你想要模拟的 bean?注意:如果您使用@Mock,则需要在每次测试前通过在测试类中调用MockitoAnnotations.initMocks(this) 来初始化这些模拟。
  • 您为什么不简单地手动接线进行测试?
  • 如果我想手动连接它们,我需要更改类以允许我注入模拟对象。 Springockito 允许您做的是使用现有的自动装配机制来注入模拟。
  • 你为什么要换班?如果是通过构造函数注入的,只需要调用构造函数即可。如果它是由 setter 注入的,则只需要调用 setter 即可。如果它使用字段注入,您只需要在测试中使用@Mock@InjectMocks 注释(这也适用于构造函数和setter 注入)。

标签: java spring integration-testing mockito spring-java-config


【解决方案1】:

从现在未维护(在撰写本文时)的 Spingockito 注释转移到 Mockito,我们有一种非常简单的方法:

@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration
public class MyTestClass {

    @Mock MockInterface mockObj;

    // test code
}

如果您使用的是真实对象,但想模拟其中的依赖项,例如使用 DAO 测试服务层:

@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration
public class MyTestClass {

    @InjectMocks RealService;

    @Mock MockDAO mockDAO;

    // test code
}

最后,这也可以应用于 Spring-boot,但在 setUp() 中使用注解初始化,直到支持多个类运行器:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyMainSpringBootClass.class)
public class MyTestClass {

    @InjectMocks RealService;

    @Mock MockDAO mockDAO;

    @Before
    public final void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
    }

    // test code
}

【讨论】:

  • 请考虑解释如何在投反对票时改进这篇文章。
【解决方案2】:

已过时且已弃用!

在 Spring Boot 1.4 中了解 mocking and spying

另请阅读@ethesx 答案, Springockito 无人维护

旧答案

现在可以使用Springockito-annotations. 在没有任何 XML 文件的情况下模拟 Spring 应用程序。此解决方案也适用于 Spring Boot

import static org.mockito.BDDMockito.*;
import org.kubek2k.springockito.annotations.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, 
     loader = SpringockitoAnnotatedContextLoader.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MainControllerTest {

    @Autowired
    MainController mainController;

    @Autowired
    @ReplaceWithMock
    FooService fooService;

    @Test
    public void shouldGetBar() {
        //given
        given(fooService.result("foo")).willReturn("bar");

        //when
        Bar bar build = fooService.getBar("foo");

        //then
        assertThat(bar).isNotNull();
    }
}

依赖:org.kubek2k:springockito-annotations:1.0.9

【讨论】:

  • 我没有看到它是如何与 Spring-boot 一起工作的。使用您的方法时,spring-boot 不会被初始化。
【解决方案3】:

看来SpringockitoContextLoader 扩展了GenericXmlContextLoader,它被描述为:

从 XML 资源读取 bean 定义的 AbstractGenericContextLoader 的具体实现。

因此,您目前仅限于 xml bean 定义。

您可以编写自己的上下文加载器,从 SpringockitoContextLoader 类中获取相关部分。看看here 开始吧,也许你可以扩展AnnotationConfigContextLoader 例如?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 2014-04-16
    • 2019-08-11
    相关资源
    最近更新 更多