【问题标题】:java.lang.AssertionError: Status expected:<200> but was:<404> in Junit testjava.lang.AssertionError: Status expected:<200> but was:<404> in Junit test
【发布时间】:2026-01-23 07:35:01
【问题描述】:

我想为 Rest api 创建 JUnit 测试并生成 api 文档。我想测试这段代码:

休息控制器

@RestController
@RequestMapping("/transactions")
public class PaymentTransactionsController {

@Autowired
private PaymentTransactionRepository transactionRepository;

@GetMapping("{id}")
    public ResponseEntity<?> get(@PathVariable String id) {
        return transactionRepository
                .findById(Integer.parseInt(id))
                .map(mapper::toDTO)
                .map(ResponseEntity::ok)
                .orElseGet(() -> notFound().build());
    }
}

存储库接口

public interface PaymentTransactionRepository extends CrudRepository<PaymentTransactions, Integer>, JpaSpecificationExecutor<PaymentTransactions> {

    Optional<PaymentTransactions> findById(Integer id);
}

我尝试用 mockito 实现这个 JUnit5 测试:

@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
@SpringBootTest(classes = PaymentTransactionsController.class)
@WebAppConfiguration
public class PaymentTransactionRepositoryIntegrationTest {
    .....
    private MockMvc mockMvc;

    @MockBean
    private PaymentTransactionRepository transactionRepository;

    @BeforeEach
    void setUp(WebApplicationContext webApplicationContext,
              RestDocumentationContextProvider restDocumentation) {

        PaymentTransactions obj = new PaymentTransactions(1);

        Optional<PaymentTransactions> optional = Optional.of(obj);      

        PaymentTransactionRepository processor = Mockito.mock(PaymentTransactionRepository.class);
        Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);       

        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
              .apply(documentationConfiguration(restDocumentation))
              .alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
              .build();
    }

    @Test
    public void testNotNull() {
        assertNotNull(target);
    }

    @Test
    public void testFindByIdFound() {
        Optional<PaymentTransactions> res = target.findById(Integer.parseInt("1"));
//        assertTrue(res.isPresent());
    }

    @Test
    public void indexExample() throws Exception {
            this.mockMvc.perform(get("/transactions").param("id", "1"))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/xml;charset=UTF-8"))
                .andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
                    responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
    }
}

我得到错误:

java.lang.AssertionError: Status expected:<200> but was:<404>

向上述代码发出 GET 请求的正确方法是什么? 可能我需要在发回消息时添加响应 OK?

【问题讨论】:

  • status 404 表示未找到您对“/transactions”的请求,可以使用`MockMvcRequestBuilders.get("/transactions/{id}", 1) `...
  • 我也试过了,但我得到了java.lang.AssertionError: Status expected:&lt;200&gt; but was:&lt;404&gt;
  • @PeterPenzov 您是否检查过您的 webApplicationContext 是否已正确初始化和注入?
  • 不,我该怎么做?

标签: java spring spring-boot junit5 spring-restdocs


【解决方案1】:

而不是 @PostMapping 和 @GetMapping 导致同样的问题,而控制器中的 @RequestMapping 帮助

【讨论】:

  • 这对我有用,为什么???
【解决方案2】:

嗨,在我的情况下,我需要控制器的 @MockBean 和所有自动连接的服务;)

【讨论】:

    【解决方案3】:

    这是一个路径变量,所以不要使用参数值,请使用路径变量。

    对于MvcResult导入,可以导入org.springframework.test.web.servlet

    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.MvcResult;
    

    ...

    given(target.findById(anyInt())).willReturn(Optional.of(new PaymentTransactions(1))).andReturn();
    
    MvcResult result = this.mockMvc.perform(get("/transactions/1")
                    .accept("application/xml;charset=UTF-8")).andReturn();
    
    String content = result.getResponse().getContentAsString();
    
    this.mockMvc.perform(get("/transactions/1")
                .accept("application/xml;charset=UTF-8"))
                .andExpect(status().isOk())
                .andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
                    responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
    

    【讨论】:

    • 我在这一行收到java.lang.AssertionError: Status expected:&lt;200&gt; but was:&lt;404&gt; .andExpect(status().isOk()) 知道为什么吗?
    • 您能否尝试在this.mockMvc.perform given(target.findById(anyInt())).willReturn(Optional.of(new PaymentTransactions(1))); 之前添加以下行,看看是否可行?
    • @PeterPenzov 当然,请尝试一下。
    • 我试过了,但我再次收到错误 404。知道如何调试它吗?
    • 是的,你绝对可以。我更新了答案,请看。
    【解决方案4】:

    你可以试试这个吗..

    public class PaymentTransactionsControllerTest {
    
    private MockMvc mvc;
    
    @InjectMocks
    PaymentTransactionsController paymentTransactionsController;
    
    @MockBean
    private PaymentTransactionRepository processor;
    
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(paymentTransactionsController).build();
    }
    
    @Test
    public void indexExample() throws Exception {
    
        PaymentTransactions obj = new PaymentTransactions(1);
        Optional<PaymentTransactions> optional = Optional.of(obj);  
    
        Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional); 
    
        MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/transactions/{id}", 1))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
    
        Assert.assertNotNull(result.getResponse().getContentAsString());
    }
    }
    

    【讨论】:

    • 我在这一行得到 NPE MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/transactions/{id}", 1))
    • 你能在你的设置中用这个代码替换吗,我认为 PaymentTransactionsController 没有注入你的测试,所以你得到 NPE @Before public void setUp() { MockitoAnnotations.initMocks(this); mvc = MockMvcBuilders.standaloneSetup(new PaymentTransactionRepository()).build(); }
    • 我的 git repo 中有用于单元测试的小演示......它可以帮助你......github.com/prameshbhattarai/spring-boot-demo
    • 我在同一行再次获得 NPE。
    • 你能给我提供你的异常的堆栈跟踪吗......你也检查了我的回购......