【问题标题】:How to autowire field in static @BeforeClass?如何在静态@BeforeClass 中自动装配字段?
【发布时间】:2015-06-03 02:51:06
【问题描述】:
@RunWith(SpringJUnit4ClassRunner.class)
public void ITest {
    @Autowired
    private EntityRepository dao;

    @BeforeClass
    public static void init() {
        dao.save(initialEntity); //not possible as field is not static
    }
}

如何让我的服务已经注入到静态初始化类中?

【问题讨论】:

标签: java spring junit spring-test


【解决方案1】:

使用 Junit 5,您可以做到这一点(@BeforeAll 而不是 @BeforeClass)

public void ITest {
    @Autowired
    private EntityRepository dao;

    @BeforeAll
    public static void init(@Autowired EntityRepository dao) {
        dao.save(initialEntity); //possible now as autowired function parameter is used
    }
}

离开该字段意味着它可以用于其他测试

【讨论】:

    【解决方案2】:

    我一直在使用的一种解决方法是使用 @Before 和一个标志来跳过它为每个测试用例执行的操作

    @RunWith(SpringJUnit4ClassRunner.class)
    public class BaseTest {
    
    @Autowired
    private Service1 service1;
    
    @Autowired
    private Service2 service2;
    
    private static boolean dataLoaded = false;
    
    @Before
    public void setUp() throws Exception {
    
        if (!dataLoaded) {
            service1.something();
            service2.somethingElse();
            dataLoaded = true;
        }
      }
    }
    

    【讨论】:

    • 我一直在这样做,但确实必须有更好的方法,尤其是当您依赖注入/自动连接的字段时,因为在这种情况下@BeforeClass 将不起作用。跨度>
    • 执行测试后的@AfterClass 部分怎么样。有什么策略可以像第一部分一样保持简单吗?
    • @emecas 做与帖子提及相同的事情,但使用@After 而不是@Before,并且每次调用它时,您都会更新一个测试计数器,当测试计数器转到您的最后一个时测试,执行你的语句。
    • 这种方法的最大问题是使用 @After 注释做同样的解决方法。为此,必须动态了解测试次数。
    【解决方案3】:

    在我看来,您正在尝试在测试之前填充数据库。

    我会尝试两种选择:

    • 如果您可以将初始脚本提取到 sql 文件(如果您可以选择不使用存储库 bean),您可以使用 this approach 并使用 @Sql 注释您的测试
    • 您可以探索DbUnit,这里是link to spring dbunit connector,它正是这样做的,并帮助您在测试前填充数据库。这是一个github link,用于在 spring 测试框架和 dbunit 之间进行集成。完成此操作后,您将拥有 @DatabaseSetup@DatabaseTearDown,它们将在 DB 上执行您需要的操作

    我知道这并不能回答如何在静态 @BeforeClass 中注入 bean,但它看起来正在解决您的问题。

    更新: 我最近在我的项目中遇到了同样的问题并挖出了this article 这对我有帮助,我认为这是处理这类问题的优雅方式。您可以使用侦听器扩展 SpringJUnit4ClassRunner,该侦听器可以使用您定义的所有 bean 进行实例级别设置。

    【讨论】:

    • 最后一个链接(在最后一段中)已损坏。根据您的解释,发生了什么令人难过的事情,因为它似乎有有趣的信息:(
    【解决方案4】:

    适用于 Spring 2.x 版本的 UPD。

    Spring 2.x 支持 Junit 5 Jupiter 的新功能 SpringExtension,您所要做的就是:

    1. @ExtendWith(SpringExtension.class)声明你的测试类

    2. 用 bean 注入您的 @BeforeAll(在 JUnit 5 中替换 @BeforeClass

    例如:

    @ExtendWith(SpringExtension.class)
    ...
    public void ITest {
    
        @BeforeAll
        public static void init(@Autowired EntityRepository dao) {
            dao.save(initialEntity);
        }
    
    }
    

    假设您使用 Spring 2.x 正确配置了 JUnit 5 Jupiter

    更多信息在这里:https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-junit-jupiter-extension

    【讨论】:

    • 听起来很有希望!
    【解决方案5】:

    要回答这个问题,我们应该回顾一下 Spring 2.x 版本。

    如果你想在@BeforeTest 类中“自动装配”一个bean,你可以使用ApplicationContext 接口。我们来看一个例子:

    @BeforeClass
        public static void init() {
            ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
            EntityRepository dao2 = (EntityRepository) context.getBean("dao");
            List<EntityRepository> all = dao2.getAll();
            Assert.assertNotNull(all);
        }
    

    发生了什么:使用ClassPathXmlApplicationContext,我们正在实例化包含在application-context.xml 文件中的所有bean。

    使用context.getBean(),我们读取指定的bean(它必须与bean的名称匹配!);然后您可以将其用于初始化。

    您应该给 bean 另一个名称(即dao2!)否则 Spring 正常的“自动装配”无法在预定义的 bean 上工作。

    附带说明,如果您的测试扩展了AbstractTransactionalJUnit4SpringContextTests,您可以使用executeSqlScript(sqlResourcePath, continueOnError) 进行一些初始化;方法,因此您不必依赖还必须单独测试的类/方法。

    【讨论】:

    • 我自己无法实例化ApplicationContext,因为我还使用@IntegrationTest 在测试期间自动连接我的普通@EnableAutoConfiguration 类(基于注释的配置)。
    • 那你为什么不用executeSqlScript呢?它是一个静态方法,当您扩展 AbstractTransactionalJUnit4SpringContextTests 类时可以免费获得。
    • 这个问题当然只是一个例子。我也可以在@BeforeClass 中执行任何逻辑,而不仅仅是数据库初始化...
    • 我认为在静态方法中只能调用静态变量。所以最好的办法是创建一个带有静态方法的服务来执行你的逻辑。例如,您可以创建一个自动装配内容的服务,以及返回自动装配类的静态 getter。
    【解决方案6】:

    如果您只想在测试中使用一些数据库数据,您也可以模拟存储库并使用 @Before Narain Mittal 描述的解决方法:

    @RunWith(SpringJUnit4ClassRunner.class)
    public void ITest {
        @MockBean
        private EntityRepository dao;
    
        @Before
        public static void init() {
            when(dao.save(any())).thenReturn(initialEntity);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-19
      • 2012-06-11
      • 2019-01-07
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 1970-01-01
      相关资源
      最近更新 更多