[英]@Autowired Injected dependency in Junit Test is always null
In a simple test class like the one below:在一个简单的测试 class 中,如下所示:
@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));
}
}
With the AddressInfoLocalizer (sorry for the strange name but I had to make it up) being basically like this: 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();
}
}
}
I keep getting a NullPointerException when calling (in the test) addressInfoLocalizer.localize(ip);
调用(在测试中)
addressInfoLocalizer.localize(ip);
, ,
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)
while debugging I can actually see that the addressInfoLocalizer
object is null
.在调试时,我实际上可以看到
addressInfoLocalizer
object 是null
。
I've created other classes the same way, but only this one seems to have that problem, what could be wrong?我以同样的方式创建了其他类,但似乎只有这个类有这个问题,有什么问题吗?
What I found out is that not always the @SpringBootTest is enough, in some classes/cases (to be honest I don't have a 100% clear idea so I'm not gonna say stupidities) it is needed that you manually choose the test-runner, like below:我发现@SpringBootTest 并不总是足够的,在某些类/情况下(老实说,我没有 100% 清晰的想法,所以我不会说愚蠢),需要手动选择测试运行器,如下所示:
@SpringBootTest
@RunWith(SpringRunner.class)
public class FooTest {
...
}
Keep in mind that if you decide to instantiate a dependency by yourself then Spring won't be able to inject all the needed classes, and then you'd need to change the runner into something like @RunWith(MockitoJUnitRunner.class)
请记住,如果您决定自己实例化一个依赖项,那么 Spring 将无法注入所有需要的类,然后您需要将运行器更改为类似
@RunWith(MockitoJUnitRunner.class)
(credits to JUNIT Autowired instance is always null ) (归功于JUNIT 自动装配实例始终为 null )
Better approach is to use spring's underlying mock beans.更好的方法是使用 spring 的底层模拟 bean。
@SpringBootTest(classes= AddressInfoLocalizer.class)
this is actually the new recommended way.这实际上是新的推荐方式。
Two things here:这里有两件事:
@ExtendWith(MockitoExtension.class)
or @RunWith(MockitoJUnitRunner.class)
so that your components will be loaded in spring context.@ExtendWith(MockitoExtension.class)
或@RunWith(MockitoJUnitRunner.class)
以便您的组件将在 spring 上下文中加载。 However ExtendWith
is preferred way to initialize beans/components.ExtendWith
是初始化 bean/组件的首选方式。 Because the later(RunWith) loads the entire spring context which might take more timeSo, your code should look something like:因此,您的代码应类似于:
@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));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.