如何在静态@BeforeClass 中自动装配字段?

How to autowire field in static @BeforeClass?

@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
    }
}

如何在静态初始化中注入我的服务 class?

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

如果你想 "autowire" 你的 @BeforeTest 中的一个 bean class 你可以使用 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 文件中包含的所有 beans。

使用 context.getBean() 我们读取指定的 bean(它必须匹配 bean 的名称!);然后你可以用它来进行初始化。

您应该给 bean 另一个名称(即 dao2!)否则 Spring 正常 "autowired" 无法在预定义的 bean 上工作。

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

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

我会尝试两种选择:

  • 如果您可以将初始脚本提取到 sql 文件(如果您可以选择不使用存储库 bean),则可以使用 this approach 并使用 @Sql[= 注释您的测试30=]
  • 您可以探索 DbUnit and here is link to spring dbunit connector which is doing exactly that and helping you populate DB before tests. Here is a github link 在 spring 测试框架和 dbunit 之间进行集成。在你这样做之后你有 @DatabaseSetup@DatabaseTearDown 这将在你需要的数据库上做事

我知道这并没有回答如何在静态中注入 bean @BeforeClass 但是形成代码看起来它正在解决你的问题。

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

我一直在使用的一种解决方法是使用 @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;
    }
  }
}

Spring 2.x 版本更新。

Spring 2.x 支持 Junit 5 Jupiter 的新功能 SpringExtension,您只需:

  1. @ExtendWith(SpringExtension.class)

  2. 声明你的测试class
  3. 用 bean

  4. 注入您的 @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

使用 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
    }
}

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

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

@RunWith(SpringJUnit4ClassRunner.class)
public void ITest {
    @MockBean
    private EntityRepository dao;

    @Before
    public static void init() {
        when(dao.save(any())).thenReturn(initialEntity);
    }
}