[英]Spring - How to properly use @Autowired to prevent controller / MockMvc from being null?
I'm attempting to run some unit tests and encountering an issue that I am sure stems from a misunderstanding about autowiring.我正在尝试运行一些单元测试并遇到一个问题,我确信该问题源于对自动装配的误解。 I have a unit test class in which I am trying to use
@Autowired
on a MockMvc and a REST controller -- both of which end up being null.我有一个单元测试类,我试图在其中使用
@Autowired
在 MockMvc 和 REST 控制器上——这两个最终都是空的。
I have seen some sources try to explain why this can happen (including this More of Less post and a helpful StackOverflow post that has given me some insight but hasn't completely helped me solve my problem).我已经看到一些来源试图解释为什么会发生这种情况(包括这篇更多的更少的帖子和一个有用的StackOverflow 帖子,它给了我一些见解,但并没有完全帮助我解决我的问题)。
Below is relevant source code from a sample project I've made to recreate this problem.以下是我为重现此问题而制作的示例项目中的相关源代码。
ManagerControllerTest.java ManagerControllerTest.java
@RunWith(SpringRunner.class)
@WebMvcTest(ManagerController.class)
public class ManagerControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private Manager manager;
@Autowired
private ManagerController controller;
@Test
public void controllerNotNull() throws Exception {
assertThat(controller).isNotNull();
}
@Test
public void testStoreSomething() throws Exception {
String path = "/manager/store-something/";
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(path)
.characterEncoding("UTF-8")
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(builder).andReturn();
assertEquals(HttpStatus.CREATED, result.getResponse().getStatus());
}
}
The controllerNotNull()
test results in controllerNotNull()
测试结果
java.lang.AssertionError: Expecting actual not to be null
java.lang.AssertionError:期望实际不为空
Although, curiously, when I created a new Gradle project in Java and imported my sample code from this post into it, controllerNotNull()
passes.虽然奇怪的是,当我用 Java 创建一个新的 Gradle 项目并将我的示例代码从这篇文章导入到其中时,
controllerNotNull()
通过了。
And testStoreSomething()
results in和
testStoreSomething()
结果
java.lang.NullPointerException at com.example.sandbox.rest.ManagerControllerTest.testStoreSomething(ManagerControllerTest.java:46)
java.lang.NullPointerException 在 com.example.sandbox.rest.ManagerControllerTest.testStoreSomething(ManagerControllerTest.java:46)
And here in lies the question: What am I misunderstanding?问题就在这里:我误解了什么? What am I doing wrong?
我究竟做错了什么? I can remove the
@Autowired
from the controller and just instantiate it with new ManagerController()
but I am left with MockMvc issue.我可以从控制器中删除
@Autowired
并使用new ManagerController()
实例化它,但我留下了 MockMvc 问题。
ManagerController.java管理器控制器.java
@Controller
@RequestMapping(value = "/manager/")
public class ManagerController {
Manager manager = new Manager(new StringStorage());
@PostMapping(value = "store-something")
private ResponseEntity<?> storeSomething(String str) {
manager.storeSomething(str);
return new ResponseEntity<>(CREATED);
}
}
Manager.java管理器
public class Manager {
private final Storage storage;
public Manager(Storage storage) {
this.storage = storage;
}
public void storeSomething(String str) {
storage.store(str);
}
}
Storage.java存储.java
public interface Storage {
void store(String str);
}
StringStorage.java字符串存储
public class StringStorage implements Storage {
Map<String, String> stringMap;
@Override
public void store(String str) {
stringMap.put(str, str);
}
}
Application.java应用程序.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
build.gradle Which has been edited from the original post (to use JUnit4) but the problem remains. build.gradle已从原始帖子(使用 JUnit4)中编辑,但问题仍然存在。
repositories {
jcenter()
}
apply plugin: 'java'
apply plugin: 'eclipse'
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.0.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: '2.0.0.RELEASE'
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.0.0.RELEASE'
testImplementation 'org.junit.jupiter:junit-jupiter-api:4.0.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:4.0.0'
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.17.0'
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: "4.0.0"
testCompile group: 'org.junit.platform', name: 'junit-platform-launcher', version: "1.3.1"
}
@RestController
@RequestMapping(value = "/manager")
public class ManagerController {
@Autowired
Manager manager;
@PostMapping(value = "/store-something")
private ResponseEntity<?> storeSomething(String str) {
manager.storeSomething(str);
return new ResponseEntity<>(CREATED);
}
}
@Component
public class Manager {
@Autowired
private Storage storage;
public void storeSomething(String str) {
storage.store(str);
}
}
public interface Storage {
void store(String str);
}
@Service
public class StringStorage implements Storage {
Map<String, String> stringMap = new HashMap<>();
@Override
public void store(String str) {
stringMap.put(str, str);
}
}
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The test class :测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ApplicationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(post("/manager/store-something")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello World")));
}
}
add annotation AutoConfigureMockMvc to your test class将注释 AutoConfigureMockMvc 添加到您的测试类
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
public class ManagerControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private Manager manager;
@Autowired
private ManagerController controller;
@Test
public void controllerNotNull() throws Exception {
assertThat(controller).isNotNull();
}
@Test
public void testStoreSomething() throws Exception {
this.mvc.perform(get("/manager/store-something/"))
.contentType(MediaType.APPLICATION_JSON)
.andExpect(status().isOk())
}
Alternatively you can also use TestRestTemplate with @SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)或者,您也可以将 TestRestTemplate 与 @SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT) 一起使用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.