You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JUnit Mockito测试Rest API时ApplicationContext加载失败求助

Hey there! Let's break down why your ApplicationContext is failing to load and fix your test case step by step.

1. Annotation Conflicts Are Breaking Context Loading

Your test class has conflicting annotations that are confusing Spring's context initialization:

  • @WebMvcTest is purpose-built for testing Spring MVC controllers and automatically uses SpringRunner under the hood—you don't need to add @RunWith(SpringJUnit4ClassRunner.class) explicitly.
  • When using @WebMvcTest, Spring creates a sliced context containing only web-related beans (like your ItemController). But you're mixing it with @InjectMocks, a Mockito annotation for manually injecting mocks into a class. This creates a conflict because Spring is already trying to manage the ItemController bean, and you're trying to instantiate a separate instance with Mockito.

2. Your Mocking Approach Is Misaligned

Right now, you're mocking the ItemController method directly, which defeats the point of testing the controller. You should mock the controller's dependency (ItemService) instead, then verify that the controller correctly uses this dependency to handle requests.


Fix Option 1: Proper Integration Test with @WebMvcTest

This tests the actual HTTP endpoint behavior using Spring's MockMvc to simulate requests:

package com.example.demo.controller;

import com.example.demo.entities.Item;
import com.example.demo.service.ItemService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(ItemController.class)
public class ItemControllerTest {

    @Autowired
    private MockMvc mockMvc;

    // Use @MockBean to add a mocked ItemService to Spring's sliced context
    @MockBean
    private ItemService itemService;

    @Test
    public void itemGetById_ReturnsExpectedItem() throws Exception {
        // Arrange: Set up test data and mock service behavior
        Item testItem = new Item();
        testItem.setItemId(10L);
        testItem.setItemName("Wireless Mouse");
        testItem.setItemPrice(49);

        when(itemService.getItem(10L)).thenReturn(testItem);

        // Act & Assert: Simulate GET request and validate response
        mockMvc.perform(get("/item/get")
                        .param("id", "10"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.itemId").value(10))
                .andExpect(jsonPath("$.itemName").value("Wireless Mouse"))
                .andExpect(jsonPath("$.itemPrice").value(49));
    }
}

Fix Option 2: Pure Unit Test (No Spring Context)

If you just want to test the controller's core logic without loading a Spring context, use Mockito's runner instead:

package com.example.demo.controller;

import com.example.demo.entities.Item;
import com.example.demo.service.ItemService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class) // Use Mockito's runner instead of Spring
public class ItemControllerUnitTest {

    @Mock
    private ItemService itemService;

    @InjectMocks
    private ItemController itemController;

    @Test
    public void getById_ReturnsItemFromService() {
        // Arrange
        Item testItem = new Item();
        testItem.setItemId(10L);
        when(itemService.getItem(10L)).thenReturn(testItem);

        // Act
        Item result = itemController.getById(10L);

        // Assert
        assertEquals(testItem, result);
    }
}

Quick Extra Notes

  • In your ItemController, the getById method uses @GetMapping("/get") with an unannotated id parameter. This expects a query parameter like ?id=10. If you want a path variable (e.g., /item/get/10), update the method to:
    @GetMapping("/get/{id}")
    public Item getById(@PathVariable Long id) {
        return itemService.getItem(id);
    }
    
    Then adjust your test to use get("/item/get/10") instead of adding a query param.
  • Your ItemService uses repository.findById(id).get() which throws a NoSuchElementException if the item doesn't exist. Consider adding error handling (like returning null or throwing a custom exception) and a test case for that scenario.

内容的提问来源于stack exchange,提问作者Pankaj Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:29:18