SpringBoot+Mock Mvc测试web接口增删改查、导入导出

需求:

        使用Mock Mvc单元测试web接口的增删改查、导入、导出功能,涵盖登录 token header赋值等全流程

1,引入核心依赖

<!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

2,编写登录抽象父类

@Component
public class AbstractControllerTest {
    private static final String USER_NO = "xxxx";
    private static final String PASSWORD = "xxxx";
    private static final String LOGIN_URL_DEV = ConstantsProperties.UAC_HOST+"/xxxx/auth/login";
    public static final String FILE_ROOT = System.getProperty("user.dir")+"/src/test/java/com/xxx/xxxx/controller/file";
    @Autowired
    private WebApplicationContext webApplicationContext;
    @Autowired
    private ApiGlobalVarsFilter apiGlobalVarsFilter;
    public MockMvc mockMvc;
    @Autowired
    RestTemplate restTemplate;
    public String token;
    @Before
    public void setupMockMvc(){
        //获取登录token
        LoginRequest request = new LoginRequest();
        request.setUserNo(USER_NO);
        request.setPassword(PASSWORD);
        ResponseEntity<LoginResponse> loginResponseResponseEntity =
                restTemplate.postForEntity(LOGIN_URL_DEV, request, LoginResponse.class);
        token = loginResponseResponseEntity.getBody().getToken();

        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .apply(SecurityMockMvcConfigurers.springSecurity())
                .addFilters(apiGlobalVarsFilter).build();
    }



}

3,编写单元测试核心类

@ActiveProfiles("dev")
@RunWith(SpringRunner.class)
@SpringBootTest(classes = YmsApplication.class)
@Slf4j
public class TCommTagConfigControllerTest extends AbstractControllerTest{

    @Autowired
    TCommTagConfigService tCommTagConfigService;

    @Test
    public void login(){
        log.info("登录token为:{}",token);
    }

    @Test
    public void save() throws Exception {
        TCommTagConfigReqBody tCommTagConfigReqBody = new TCommTagConfigReqBody();
        tCommTagConfigReqBody.setTag("测试1");
        tCommTagConfigReqBody.setOwner("test");
        String requestBody = JSONUtil.toJsonStr(tCommTagConfigReqBody);
        mockMvc.perform(
                MockMvcRequestBuilders.post("/v1/tagConfig/save")
                        .contentType(MediaType.APPLICATION_JSON).content(requestBody)
                        .header("Authorization",token)
        ).andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void update() throws Exception {
        TCommTagConfigReqBody tCommTagConfigReqBody = new TCommTagConfigReqBody();
        tCommTagConfigReqBody.setId(62L);
        tCommTagConfigReqBody.setTag("测试11");
        tCommTagConfigReqBody.setOwner("test2");
        String requestBody = JSONUtil.toJsonStr(tCommTagConfigReqBody);
        mockMvc.perform(
                MockMvcRequestBuilders.post("/v1/tagConfig/save")
                        .contentType(MediaType.APPLICATION_JSON).content(requestBody)
                        .header("Authorization",token)
        ).andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void delete() throws Exception {
        String ids = "63,64";
        mockMvc.perform(
                MockMvcRequestBuilders.get("/v1/tagConfig/delete?ids="+ids)
                        .contentType(MediaType.APPLICATION_JSON)
                        .header("Authorization",token)
        ).andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void getList() throws Exception {
        TCommTagConfigPageReqBody tCommTagConfigPageReqBody = new TCommTagConfigPageReqBody();
        tCommTagConfigPageReqBody.setOwner("test");
        tCommTagConfigPageReqBody.setTag("测试");
        mockMvc.perform(
                MockMvcRequestBuilders.post("/v1/tagConfig/getList")
                        .contentType(MediaType.APPLICATION_JSON).content(JSONUtil.toJsonStr(tCommTagConfigPageReqBody))
                        .header("Authorization",token)
        ).andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void exportFile() throws Exception {
        TCommTagConfigPageReqBody tCommTagConfigPageReqBody = new TCommTagConfigPageReqBody();
        tCommTagConfigPageReqBody.setIsExcel("1").setIsEmpty("0").setIsConfig("1");
        tCommTagConfigPageReqBody.setOwner("test");
        tCommTagConfigPageReqBody.setTag("测试");
        mockMvc.perform(
                MockMvcRequestBuilders.post("/v1/tagConfig/export")
                        .contentType(MediaType.APPLICATION_JSON).content(JSONUtil.toJsonStr(tCommTagConfigPageReqBody))
                        .header("Authorization",token)
        ).andDo(result -> {
            //保存为文件  文件目录需要自建
            File file  = new File(FILE_ROOT+"/tag/exportFile.xlsx");
            if(!file.exists()){
                file.createNewFile();
            }
            try(FileOutputStream fileOutputStream = new FileOutputStream(file)){
                IOUtils.write(result.getResponse().getContentAsByteArray(),fileOutputStream);
            }catch (IOException e){
                log.error("文件导出失败,异常信息:{}",e.getMessage());
            }
            //assert
            MatcherAssert.assertThat(file.exists(), Matchers.equalTo(true));
            MatcherAssert.assertThat(file.length(), Matchers.greaterThan(1024L));
        });
    }

    @Test
    public void importFile() throws Exception {
        //保存为文件  文件目录需要自建
        File file  = new File(FILE_ROOT+"/tag/Tag Config.xlsx");
        ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.fileUpload("/v1/tagConfig/import")
                        .file(new MockMultipartFile("file", "Tag Config.xlsx",
                                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                                new FileInputStream(file)))
                .header("Authorization",token)
        );
        MvcResult mvcResult = resultActions.andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
        String result = new String(mvcResult.getResponse().getContentAsByteArray(),"UTF-8");
        log.info("==========结果为:{}==========" ,result);
    }
}

参照:

MockMVC测试上传文件功能_mockmultipartfile怎么测试上传的excel文件-CSDN博客

SpringBoot基础之MockMvc单元测试 - 知乎 (zhihu.com)

MultipartFile的使用小结 - 邱明成 - 博客园 (cnblogs.com)

设置 MockMvc 和 Spring Security :: Spring Security Reference (springdoc.cn)

Spring Boot干货系列:(十二)Spring Boot使用单元测试 - 知乎 (zhihu.com)

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
很抱歉,我是一名AI语言模型,无法使用代码进行编程,以下是一个使用mock react ts hooks做增删改查的示例: ``` import React, { useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; interface Todo { id: string; title: string; completed: boolean; } const initialTodos: Todo[] = [ { id: uuidv4(), title: 'Learn React', completed: false }, { id: uuidv4(), title: 'Learn TypeScript', completed: false }, { id: uuidv4(), title: 'Build a Todo App', completed: false }, ]; const App: React.FC = () => { const [todos, setTodos] = useState<Todo[]>(initialTodos); const [newTodo, setNewTodo] = useState<string>(''); const handleNewTodoChange = (event: React.ChangeEvent<HTMLInputElement>) => { setNewTodo(event.target.value); }; const handleAddTodo = () => { if (newTodo.trim() !== '') { setTodos([...todos, { id: uuidv4(), title: newTodo, completed: false }]); setNewTodo(''); } }; const handleDeleteTodo = (id: string) => { setTodos(todos.filter(todo => todo.id !== id)); }; const handleToggleTodo = (id: string) => { setTodos( todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo, ), ); }; const handleEditTodo = (id: string, newTitle: string) => { setTodos( todos.map(todo => (todo.id === id ? { ...todo, title: newTitle } : todo)), ); }; return ( <div> <h1>Todo App</h1> <input type="text" value={newTodo} onChange={handleNewTodoChange} /> <button onClick={handleAddTodo}>Add Todo</button> <ul> {todos.map(todo => ( <li key={todo.id}> <input type="checkbox" checked={todo.completed} onChange={() => handleToggleTodo(todo.id)} /> <input type="text" value={todo.title} onChange={event => handleEditTodo(todo.id, event.target.value)} /> <button onClick={() => handleDeleteTodo(todo.id)}>Delete</button> </li> ))} </ul> </div> ); }; export default App; ``` 在这个示例中,我们定义了一个`Todo`类型,它包含一个`id`、一个`title`和一个`completed`属性。我们使用`useState`钩子来管理一个`todos`数组和一个`newTodo`字符串,`todos`数组包含所有的todo项,`newTodo`字符串保存用户输入的新todo项的标题。 我们使用`handleNewTodoChange`函数来处理新todo标题的变化。当用户在输入框中输入新标题时,我们使用`setNewTodo`来更新`newTodo`的值。 当用户点击“添加Todo”按钮时,我们使用`handleAddTodo`函数来添加新的todo项。如果`newTodo`不是空字符串,我们将一个新的`Todo`对象添加到`todos`数组中,并将`newTodo`设置为空字符串。 当用户点击“删除”按钮时,我们使用`handleDeleteTodo`函数来删除todo项。我们使用`setTodos`和`filter`方法来过滤掉与传递的id相匹配的todo项。 当用户切换复选框时,我们使用`handleToggleTodo`函数来切换todo项的完成状态。我们使用`setTodos`和`map`方法来更新与传递的id相匹配的todo项的完成状态。 当用户编辑todo项的标题时,我们使用`handleEditTodo`函数来更新todo项的标题。我们使用`setTodos`和`map`方法来更新与传递的id相匹配的todo项的标题。 最后,我们在render函数中渲染了一个todo列表,包含每个todo项的复选框、文本框、删除按钮和编辑按钮。当用户切换复选框时,我们调用`handleToggleTodo`函数。当用户编辑文本框中的标题时,我们调用`handleEditTodo`函数。当用户点击“删除”按钮时,我们调用`handleDeleteTodo`函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Loren_云淡风轻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值