【问题标题】:How to create a general MockMvc class for multiple test classes?如何为多个测试类创建一个通用的 MockMvc 类?
【发布时间】:2021-12-19 03:07:11
【问题描述】:

我正在为许多不同的 Spring 控制器编写端到端测试。现在,我正在尝试编写一个包含 MockMvc 执行方法的通用测试类。我有需要在不同控制器中调用的端点,我不想复制粘贴代码,并且在每个测试类中都有一个 MockMvc 和 ObjectMapper。

几个方法的例子:

public void saveMockDish(DishDto dishDto) throws Exception {
    mockMvc.perform(
        MockMvcRequestBuilders.post(DISH_ENDPOINT)
          .contentType(MediaType.APPLICATION_JSON)
          .content(objectMapper.writeValueAsString(dishDto)))
      .andExpect(status().isCreated());
  }


public DishDto getMockDish(Long id) throws Exception {
    MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders
        .get(DISH_ENDPOINT + "/{id}", id))
      .andExpect(status().isOk())
      .andReturn();
    String contentAsString = mvcResult.getResponse().getContentAsString();
    return objectMapper.readValue(contentAsString, new TypeReference<>() {
    });
  }

我想要完成的事情(我可以​​在另一个类中自动装配的 bean,例如 DishControllerTest 类):

@AutoConfigureMockMvc
@TestComponent
public class AppMockMcv {
  private static final String DISH_ENDPOINT = "/dishes";
  private static final String BASE_INGREDIENTS_ENDPOINT = "/base-ingredients";

  @Autowired
  private MockMvc mockMvc;
  @Autowired
  private ObjectMapper objectMapper;

  public List<DishDto> getMockDishes() throws Exception {
  ...

我想如何实例化我的测试类:

@SpringBootTest
public class DishControllerTest {

  @Autowired
  private AppMockMcv appMockMcv;

  @Test
  void testGetDishes() throws Exception {
    List<DishDto> dishes = appMockMcv.getMockDishes();
    assertEquals(4, dishes.size());
    assertNotNull(dishes);
    DishAssertions.containsDish(dishes, "Pasta Carbonara");
  }

现在我面临无法将@AutoConfigureMockMvc 与@TestComponent 一起使用的问题,在自动装配中找不到bean。我还尝试了 AppMockMcv 类中的@Component、@TestConfiguration、@SpringBootTest 注解。

当前错误,虽然不是很有用:

No qualifying bean of type 'mtv.restaurant.mock.AppMockMcv' available: 
expected at least 1bean which qualifies as autowire candidate. 
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)

我没有找到太多关于如何创建仅用于测试的 bean 以及如何将其与 AutoConfigureMockMvc 结合的信息。另外,我试图找到一种方法来扩展 MockMvc 却没有成功。

实现我想要实现的目标的正确方法是什么?

  • 弹簧靴 2.5.4

【问题讨论】:

    标签: java spring spring-boot spring-mvc spring-mvc-test


    【解决方案1】:

    我没有找到太多关于如何创建用于测试的 bean 的信息 仅,还介绍了如何将其与 AutoConfigureMockMvc 结合使用。还有,我 试图找到一种方法来扩展 MockMvc 但没有成功。

    如果你在 /test/java 下创建 bean,那么它只会在测试中使用(在大多数情况下),即使使用了组件注解。在此处查看信息 - https://docs.spring.io/spring-boot/docs/1.4.3.RELEASE/reference/html/boot-features-testing.html (40.3.2)。

    另外,我写了一些代码,例如,它可以工作(因为你没有为Spring提供配置,我只使用了@SpringBootApplication):

    包源:

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

    包src.test:

    @Component
    public class CustomMockMVc {
        public MockMvc getMockMvc() {
            return mockMvc;
        }
    
        private final MockMvc mockMvc;
    
        public CustomMockMVc(MockMvc mockMvc) {
            this.mockMvc = mockMvc;
        }
    }
    
    @SpringBootTest
    @AutoConfigureMockMvc
    public class TestComponent {
        @Autowired
        private CustomMockMVc customMockMVc;
    
        @Test
        public void testMockMvc() {
            System.out.println(customMockMVc.getMockMvc());
        }
    }
    

    【讨论】:

    • 这是解决方案,非常好。请注意,使用此解决方案后,您需要为每个@SpringBootTest 配置MockMvc,要么声明一个组件,要么使用@AutoConfigureMockMvc。这可能是因为我的 CustomMockMvc 组件仅在测试文件中。
    【解决方案2】:

    呵呵,在我开始学习 Spring Boot 之后,我往往会忘记基本的 Java...

    我想出的解决方案是我在 xControllerTest 类中 @Autowire 和 @AutoConfigureMockMvc 并创建一个 AppMockMcv @BeforeAll 测试的实例,我在其中传入 MockMvc 和 ObjectMapper。

    这样我可以调用我的请求,并且只有一个类中的 Mvc 执行方法。

    我将分享我的解决方案,但如果有人分享应该如何正确完成的解决方案,我将非常感激。

    AppMockMcv:

    public class AppMockMcv {
      private static final String DISH_ENDPOINT = "/dishes";
      private static final String BASE_INGREDIENTS_ENDPOINT = "/base-ingredients";
    
      private final MockMvc mockMvc;
      private final ObjectMapper objectMapper;
    
      public AppMockMcv(MockMvc mockMvc, ObjectMapper objectMapper) {
        this.mockMvc = mockMvc;
        this.objectMapper = objectMapper;
      }
    
      public List<DishDto> getMockDishes() throws Exception {
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders
            .get(DISH_ENDPOINT)
            .queryParam("custom", "false"))
          .andExpect(status().isOk())
          .andReturn();
        String contentAsString = mvcResult.getResponse().getContentAsString();
        return objectMapper.readValue(contentAsString, new TypeReference<>() {
        });
      }
     }
    

    DishControllerTest:

    @AutoConfigureMockMvc
    @SpringBootTest
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    public class DishControllerTest {
    
      @Autowired
      private MockMvc mockMvc;
      @Autowired
      private ObjectMapper objectMapper;
    
      private AppMockMcv appMockMcv;
    
      @BeforeAll
      public void setup() {
        appMockMcv = new AppMockMcv(mockMvc, objectMapper);
      }
    
      @Test
      void testGetDishes() throws Exception {
        List<DishDto> dishes = appMockMcv.getMockDishes();
        assertEquals(4, dishes.size());
        assertNotNull(dishes);
        DishAssertions.containsDish(dishes, "Pasta Carbonara");
      }
     }
    

    【讨论】:

      猜你喜欢
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 2015-08-19
      • 1970-01-01
      • 2012-12-23
      • 2014-08-16
      • 1970-01-01
      相关资源
      最近更新 更多