如何在 spring 启动时进行 Junit 测试

How to make Junit test in spring boot

我想测试我的其余控制器方法的行为,使用 Mockito.test。

我有以下控制器class

    @RestController
    @RequestMapping("/project/image")
    public class ImageController {
        @Autowired
        ImgService imageService;    
    
    
        @GetMapping("/getImage/{id}")
    public ResponseEntity<Image> getImageById(@PathVariable Integer id) {
        Optional<Image> img = imageService.getImageById(id);
        return new ResponseEntity<Image>(HttpStatus.OK);    
}   ....

我正在尝试对 getImageById 方法进行一些基本的单元测试,但它没有通过测试:


@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ImageControllerTest {
    @MockBean
    private ImgService service;
    @Autowired
    private MockMvc mockMvc;

    @Test
    @DisplayName("GET /Image/1 - Found")
    void testGetImageIdFound() throws Exception {
        Image mockImage = new Image(1, "mockPath", "Normal");
        doReturn(Optional.of(mockImage)).when(service).getImageById(1);        mockMvc.perform(get("/getImage/{id}",1).accept(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(jsonPath("$.id", is(1)))
    }

我收到的错误是“未设置内容类型”

这是完整的轨迹:

java.lang.AssertionError: Content type not set
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:37)
    at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:70)
    at org.springframework.test.util.AssertionErrors.assertNotNull(AssertionErrors.java:106)
    at org.springframework.test.web.servlet.result.ContentResultMatchers.lambda$contentType[=13=](ContentResultMatchers.java:83)
    at org.springframework.test.web.servlet.MockMvc.andExpect(MockMvc.java:196)
    at com.bachelor.ImageControllerTest.testGetImageIdFound(ImageControllerTest.java:61)
    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.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod[=13=](ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke[=13=](ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:212)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

我错过了什么?

你可以试试下面,你不需要 @SpringBootTest 还添加了 standaloneSetup

@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
public class ImageControllerTest {

    @Mock
    private ImgService service;

    @Autowired
    private MockMvc mockMvc;

    @InjectMocks
    private ImageController imageController; 

    @BeforeEach
    public void setup() {

        mockMvc = MockMvcBuilders.standaloneSetup(imageController).build();
    }

    @Test
    @DisplayName("GET /Image/1 - Found")
    void testGetImageIdFound() throws Exception {
        // Setup our mocked service
        Image mockImage = new Image(1, "mockPath", "Normal");
        doReturn(Optional.of(mockImage)).when(service).getImageById(1);

        // Execute the GET request
        mockMvc.perform(get("/getImage/{id}", 1).accept(MediaType.APPLICATION_JSON_UTF8))

                // Validate the response code and content type
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(header().string(HttpHeaders.LOCATION, "/getImage/1"))
                
                // Validate the returned fields
                .andExpect(jsonPath("$.physicalPath", is("mockPath")))
                .andExpect(jsonPath("$.id", is(1)))
                .andExpect(jsonPath("$.status", is("Normal")));
    }
}

正如我在评论中提到的,我解决了以下问题,现在您的测试通过了:

  • mockMvc.perform(get("/getImage/ 与 getImageById
  • 的完整 URL 不匹配
  • 您没有从该方法返回 img 对象。
  • 确保图像 class 具有 getter,以便 JSON 能够正确序列化

工作代码:

package sotestapp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@SpringBootApplication
public class TestApp {
    public static void main(String[] args) {
        SpringApplication.run(TestApp.class, args);
    }
}

@RestController
@RequestMapping("/project/image")
class ImageController {
    @Autowired
    ImgService imageService;

    @GetMapping("/getImage/{id}")
    public ResponseEntity<Image> getImageById(@PathVariable Integer id) {
        Optional<Image> img = imageService.getImageById(id);
        return ResponseEntity.of(img);
    }
}

@Service
class ImgService {
    public Optional<Image> getImageById(Integer id) {
        return Optional.of(new Image(1, "test", "test"));
    }
}

class Image {
    int id;
    String path;
    String normal;

    public Image(int id, String path, String normal) {
        this.id = id;
        this.path = path;
        this.normal = normal;
    }

    public int getId() {
        return id;
    }

    public String getPath() {
        return path;
    }

    public String getNormal() {
        return normal;
    }
}

测试:

package sotestapp;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.util.Optional;

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

@SpringBootTest
@AutoConfigureMockMvc
public class ImageControllerTest {
    @MockBean
    private ImgService service;
    @Autowired
    private MockMvc mockMvc;

    @Test
    void testGetImageIdFound() throws Exception {
        Image mockImage = new Image(1, "mockPath", "Normal");
        doReturn(Optional.of(mockImage)).when(service).getImageById(1);
        mockMvc.perform(get("/project/image/getImage/{id}", 1)
                .accept(MediaType.APPLICATION_JSON_VALUE))
                .andExpect(jsonPath("$.id", Matchers.is(1)));
    }
}