如何使 Spring 的 @Autowired 在 JUnit 5 扩展中工作? [复制]

Posted

技术标签:

【中文标题】如何使 Spring 的 @Autowired 在 JUnit 5 扩展中工作? [复制]【英文标题】:How to make Spring's @Autowired to work in JUnit 5 extensions? [duplicate] 【发布时间】:2019-01-13 18:54:40 【问题描述】:

我有一个 Spring Boot 应用程序,我正在尝试在 JUnit 5 扩展中使用 @Autowired。但是,我无法让它工作。 (@Autowired 字段为空。)有人可以帮忙吗?

下面是演示我遇到的问题的代码(重要部分是 SomeExtensionSomeTest。正如所写,mvn test 导致测试在 beforeEach 中失败。抱歉,如果我也包括在内很多。

src/test/java/somepackage/SomeExtension.java:

package somepackage;

import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SomeExtension implements BeforeEachCallback 
    @Autowired
    SomeBean bean;

    @Override
    public void beforeEach(ExtensionContext context) 
        assertNotNull(bean);
    

src/test/java/somepackage/SomeTest.java:

package somepackage;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;


@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SomeExtension.class)
class SomeTest 
    @Test
    void nothingTest() 
    

src/main/java/somepackage/SomeBean.java

package somepackage;

import org.springframework.stereotype.Component;

@Component
public class SomeBean 

src/main/java/somepackage/MainClass.java

package somepackage;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MainClass 
    public static void main(String[] args) 
        SpringApplication.run(MainClass.class, args);
    

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>fooGroupId</groupId>
    <artifactId>barArtifactId</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <!-- Don't include Junit 4 -->
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.2.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <!--
                This is copied from https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven
                This allows the surefire plugin to be able to find Junit 5 tests, so `mvn test` works.
                -->
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.21.0</version>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>1.2.0</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

@Value 也有类似的问题。如果解决方案也适用于此,那就太好了。

谢谢。

【问题讨论】:

仅供参考:这本质上是一个重复的问题,这是我的答案:***.com/a/50251190/388980 我刚刚阅读了那个问题,我发现我只需要向 SomeTest 添加一个类型为 SomeExtension 的字段,并使用 @Autowired 和 @RegisterExtension 对其进行注释。而且我不得不用@Component 注释SomeExtension。谢谢。 酷!很高兴对你有所帮助。而且……当然不客气。 并通过@SpringJUnitConfig 或只是@ContextConfiguration 来添加spring 上下文 我不会说它是重复的,因为这个问题更广泛,而 Sam 的问题更具体。你能“取消复制”这个吗? 【参考方案1】:

JUnit 5 extensions不能在其他扩展上操作,只能在测试类上操作。

所以...

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SomeExtension implements BeforeEachCallback 

    @Autowired
    SomeBean bean;

    @Override
    public void beforeEach(ExtensionContext context) 
        assertNotNull(bean);
    



@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SomeExtension.class)
class SomeTest 

    @Test
    void nothingTest() 
    


... 无法正常工作。这将:

public class SomeExtension implements BeforeEachCallback 

    @Override
    public void beforeEach(ExtensionContext context) 
        // [...]
    



@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SomeExtension.class)
class SomeTest 

    @Autowired
    SomeBean bean;

    @Test
    void nothingTest() 
    


如果您能解释为什么您需要在扩展中使用 bean,我们也可以帮助您找到解决方法。

【讨论】:

我正在尝试添加一个前置条件和后置条件,在我指定的每个类的每个测试中都必须满足这些条件。我的方法是让扩展实现 BeforeEachCallback 和 AfterEachCallback。检查前置条件和后置条件需要访问一些 bean。 @TheemathasChirananthavat:您能否编辑您的问题以澄清该用例?当您使用它时,您可以删除一些内容以使其更短:所有导入和包声明以及 SomeBeanMainClass 和 POM - 不需要它们来回答您的问题。 实际上,如果其他扩展通过@RegisterExtension 以编程方式注册,JUnit Jupiter 扩展可以与其他扩展交互。请参阅我对***.com/a/50251190/388980 的回答。 ;-) 在这种情况下为什么不直接使用SpringExtension.getApplicationContext().getBean(SomeBean.class) @Torsten +1 使用了这种方法,它完全解决了我的问题。

以上是关于如何使 Spring 的 @Autowired 在 JUnit 5 扩展中工作? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中手动新建实例中使用 @Autowired

在 Spring 中使用 @Autowired 注解时出现以下错误应该如何解决?

如何在 Spring Boot 类之间正确注入 @Autowired?

Spring MVC - @Autowired 如何工作?

Spring注解@Autowired是如何工作的?

构造函数上的 Spring @Autowired 注释如何工作?