Cucumber StepDef执行时ResultActions抛出NullPointerException求助
解决Cucumber StepDef中调用MockMvc时的NullPointerException问题
你的NullPointerException根源在于JUnit的@BeforeClass注解在Cucumber测试生命周期中不会被执行,导致mockMvc始终是null,调用mockMvc.perform()时触发空指针异常。另外,你混用了JUnit和Cucumber的测试生命周期注解,这是核心问题。
问题分析
- 你在
PersonStepDefs中使用了JUnit的@BeforeClass,但Cucumber测试是由RunMvcTest中的Cucumber.classrunner驱动的,Cucumber不会识别JUnit的@BeforeClass注解,所以setup()方法根本没执行,mockMvc一直是null。 - 虽然你给
mockMvc加了@Autowired,但如果Spring上下文没有正确初始化MockMvc实例,这个注入也会失败。
修复步骤
1. 替换JUnit钩子为Cucumber钩子
把@BeforeClass替换为Cucumber的@Before注解(注意导入的是io.cucumber.java.Before,不是JUnit的),确保在每个Scenario执行前初始化MockMvc:
修改PersonStepDefs.java中的setup方法:
// 替换原来的@BeforeClass import io.cucumber.java.Before; // ...其他代码... @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); }
2. 移除不必要的@Autowired MockMvc
既然我们手动通过WebApplicationContext构建MockMvc,就不需要再注入MockMvc了,可以把@Autowired private volatile MockMvc mockMvc;这一行删掉,避免冲突:
// 删掉这一行 // @Autowired // private volatile MockMvc mockMvc; private MockMvc mockMvc; // 直接声明即可
3. 验证Spring上下文配置
确保RunMvcTest中的@ContextConfiguration(classes = V2Application.class)指向正确的应用启动类,这样Cucumber才能正确加载Spring Web上下文。
修复后的完整PersonStepDefs.java
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import io.cucumber.java.Before; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; @WebAppConfiguration @Transactional /** * Person Step Definition class to execute Scenario contained in Person.feature * @author Lewis Jones * */ public class PersonStepDefs { @Autowired private volatile WebApplicationContext wac; private MockMvc mockMvc; private ResultActions result; /** * Runs before every scenario to initialize MockMvc */ @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @When("I add a new Person using POST at {string} with JSON:") public void i_add_a_new_Person_using_POST_at_with_JSON(String request, String json) throws Exception { result = mockMvc.perform(post(request).contentType(MediaType.APPLICATION_JSON) .content(json.getBytes())); } @Then("the response code should be {int}") public void the_response_code_should_be(Integer responseCode) throws Exception { result.andExpect(status().is(responseCode)); } }
额外建议
- 不需要在StepDef类上添加
@RunWith(SpringJUnit4ClassRunner.class),因为Cucumber测试的runner已经在RunMvcTest中指定了。 - 如果你想更简洁,可以直接使用
@AutoConfigureMockMvc注解来自动注入MockMvc,不需要手动构建,但前提是Spring上下文正确加载。
内容的提问来源于stack exchange,提问作者L Jones
相关产品推荐
相关产品推荐

