【问题标题】:@Autowired Injected dependency in Junit Test is always nullJunit 测试中的@Autowired 注入依赖项始终为空
【发布时间】:2021-08-11 06:04:49
【问题描述】:

在一个简单的测试类中,如下所示:

@SpringBootTest
@Slf4j
@ActiveProfiles("test")
public class LocalizerTest {

    @Autowired
    AddressInfoLocalizer addressInfoLocalizer;


    @Test
    public void localizeIp() {
        String ip = "8.8.8.8";
        Optional<CityResponse> response = addressInfoLocalizer.localize(ip);
        response.ifPresent(cityResponse -> log.info("{}", cityResponse));
    }

}

AddressInfoLocalizer(对不起,奇怪的名字,但我不得不弥补)基本上是这样的:


@Slf4j
@Component
public class AddressInfoLocalizer {

    @Value("${geolocalization.dbpath}")
    private String databasePath;

    private DatabaseReader database;

    @PostConstruct
    public void initialize() {
        log.info("GeoIP2 database path:{}", databasePath);
        File database = new File(databasePath);
        try {
            this.database = new DatabaseReader.Builder(database).build();
        } catch (IOException ioe) {
            this.database = null;
            log.warn("Problems encountered while initializing IP localization database, skipping resolutions");
        }

    }

    public Optional<CityResponse> localize(String ipAddressString) {
        if (isNull(database)) {
            log.warn("Attempted to resolve an IP location with database problems, skipping.");
            return Optional.empty();
        }
        try {
            InetAddress ipAddress = InetAddress.getByName(ipAddressString);
            return ofNullable(database.city(ipAddress));
        } catch (UnknownHostException uhe) {
            log.error("Unknown host {}, {}", ipAddressString, uhe.getCause());
            return Optional.empty();
        } catch (IOException ioe) {
            log.error("IO error while opening database, {}", ioe.getCause().toString());
            return Optional.empty();
        } catch (GeoIp2Exception gip2e) {
            log.error("GeoIP error, {}", gip2e.getCause().toString());
            return Optional.empty();
        }
    }
}

在调用(在测试中)addressInfoLocalizer.localize(ip); 时,我不断收到 NullPointerException,

java.lang.NullPointerException
    at com.bok.parent.LocalizerTest.localizeIp(LocalizerTest.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

在调试时,我实际上可以看到 addressInfoLocalizer 对象是 null

我用同样的方法创建了其他类,但似乎只有这个有这个问题,有什么问题吗?

【问题讨论】:

  • @SpringBootTest(classes = Application.class) 或 @ContextConfiguration(classes = AppConfig.class),试试这个。

标签: java spring spring-boot junit nullpointerexception


【解决方案1】:

我发现@SpringBootTest 并不总是足够的,在某些类/情况下(老实说,我没有 100% 清晰的想法,所以我不会说愚蠢)需要你手动选择测试运行器,如下所示:

@SpringBootTest
@RunWith(SpringRunner.class)
public class FooTest {
...
}

请记住,如果您决定自己实例化一个依赖项,那么 Spring 将无法注入所有需要的类,然后您需要将运行器更改为类似 @RunWith(MockitoJUnitRunner.class)

(感谢JUNIT Autowired instance is always null

【讨论】:

    【解决方案2】:

    更好的方法是使用 spring 的底层模拟 bean。

    @SpringBootTest(classes= AddressInfoLocalizer.class)
    

    这其实是新的推荐方式。

    【讨论】:

      【解决方案3】:

      这里有两件事:

      1. 如果您正在测试,理想的方法是模拟而不是自动装配(可能有例外)
      2. 您应该使用@ExtendWith(MockitoExtension.class)@RunWith(MockitoJUnitRunner.class) 以便您的组件将在spring 上下文中加载。但是ExtendWith 是初始化bean/组件的首选方式。因为 later(RunWith) 会加载整个 spring 上下文,这可能需要更多时间

      因此,您的代码应如下所示:

      @Slf4j
      @ActiveProfiles("test")
      @ExtendWith(MockitoExtension.class)
      public class LocalizerTest {
      
          @Mock
          AddressInfoLocalizer addressInfoLocalizer;
      
      
          @Test
          public void localizeIp() {
              String ip = "8.8.8.8";
               //Mock here.
              Optional<CityResponse> response = addressInfoLocalizer.localize(ip);
              response.ifPresent(cityResponse -> log.info("{}", cityResponse));
          }
      
      }
      

      参考/阅读更多:
      https://www.baeldung.com/mockito-junit-5-extension
      https://stackoverflow.com/questions/55276555/when-to-use-runwith-and-when-extendwith
      https://www.javadoc.io/static/org.mockito/mockito-junit-jupiter/3.10.0/org/mockito/junit/jupiter/MockitoExtension.html

      【讨论】:

        猜你喜欢
        • 2019-04-30
        • 2017-02-10
        • 1970-01-01
        • 1970-01-01
        • 2016-10-04
        • 1970-01-01
        • 2019-06-24
        • 1970-01-01
        • 2016-10-01
        相关资源
        最近更新 更多