通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(二)

发布于:2025-03-18 ⋅ 阅读:(16) ⋅ 点赞:(0)

本篇文章分为三个部分,即:
通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(一)
通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(二)
通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(完整版)



四、生成UserController的单元测试类

在aicoder的对话框内输入“生成UserController的单元测试类”指令,其就可以自动的生成了代码,示例如下:
在这里插入图片描述
生成的源码如下。

  • 添加测试依赖
    确保你的 pom.xml 文件包含以下测试依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

  • 创建单元测试类
    以下生成的单元测试类修改了包名称。
package com.win.test;

import com.win.bean.User;
import com.win.control.UserController;
import com.win.service.UserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import java.util.Arrays;
import java.util.Optional;

@Nested
@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    private User user1;
    private User user2;

    /**
     * 在每个测试方法执行之前运行的设置方法。
     * 用于初始化测试所需的用户对象。
     */
    @BeforeEach
    public void setUp() {
        // 创建用户1,ID为1,姓名为"alan",年龄为18,邮箱为"alan.chan.chn@163.com"
        user1 = new User(1L, "alan", 18, "alan.chan.chn@163.com");

        // 创建用户2,ID为2,姓名为"alanchan",年龄为18,邮箱为"alan.chan.chn@163.com"
        user2 = new User(2L, "alanchan", 18, "alan.chan.chn@163.com");
    }

    /**
     * 测试获取所有用户的方法。
     */
    @Test
    public void testGetAllUsers() throws Exception {
        // 模拟 userService 的行为
        Mockito.when(userService.getAllUsers()).thenReturn(Arrays.asList(user1, user2));

        // 发送 GET 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.get("/users")
                        .accept(MediaType.APPLICATION_JSON))
                // 验证响应状态码为 200 OK
                .andExpect(MockMvcResultMatchers.status().isOk())
                // 验证响应内容为 JSON 格式,包含两个用户对象
                .andExpect(MockMvcResultMatchers.content().json("[{\"id\":1,\"name\":\"alan\",\"age\":18,\"email\":\"alan.chan.chn@163.com\"},{\"id\":2,\"name\":\"alanchan\",\"age\":18,\"email\":\"alan.chan.chn@163.com\"}]"
                ));
    }

    /**
     * 测试 getUserById 方法的单元测试。
     * 该测试方法使用 Mockito 模拟 userService 的行为,并使用 MockMvc 发送 GET 请求以验证响应。
     * 测试包括两个场景:存在用户和不存在用户。
     */
    @Test
    public void testGetUserById() throws Exception {
        // 模拟 userService 的行为
        Mockito.when(userService.getUserById(1L)).thenReturn(Optional.of(user1));

        // 发送 GET 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.get("/users/1")
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().json("{" +
                        "\"id\":1," +
                        "\"name\":\"alan\"," +
                        "\"age\":18," +
                        "\"email\":\"alan.chan.chn@163.com\"}"));

        // 测试不存在的用户
        Mockito.when(userService.getUserById(999L)).thenReturn(Optional.empty());

        // 发送 GET 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.get("/users/999")
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isNotFound());
    }

    /**
     * 测试创建用户的方法。
     * 该测试方法使用Mockito模拟userService的行为,并使用MockMvc发送POST请求,验证响应状态和内容。
     */
    @Test
    public void testCreateUser() throws Exception {
        // 创建一个用户对象,不包含id
        User user = new User(null, "alanchanchn", 20, "alan.chan.chn@163.com");

        // 模拟 userService 的行为
        // 当调用 userService.createUser(user) 时,返回一个id为3的用户对象
        User createdUser = new User(3L, "alanchanchn", 20, "alan.chan.chn@163.com");
        Mockito.when(userService.createUser(user)).thenReturn(createdUser);

        // 发送 POST 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.post("/users")
                        .content("{\"name\":\"alanchanchn\",\"age\":20,\"email\":\"alan.chan.chn@163.com\"}")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON))
                // 验证响应状态为200 OK
                .andExpect(MockMvcResultMatchers.status().isOk())
                // 验证响应内容是否符合预期的JSON格式
                .andExpect(MockMvcResultMatchers.content().json("{" +
                        "\"id\":3," +
                        "\"name\":\"alanchanchn\"," +
                        "\"age\":20," +
                        "\"email\":\"alan.chan.chn@163.com\"" +
                        "}"));
    }

    /**
     * 测试 updateUser 方法的单元测试。
     * 该测试包括两个场景:更新存在的用户和更新不存在的用户。
     */
    @Test
    public void testUpdateUser() throws Exception {
        // 创建一个用户对象,不包含id
        User userToUpdate = new User(null, "alanchanchn", 20, "alan.chan.chn@163.com");

        // 模拟 userService 的行为
        // 当调用 userService.updateUser(1L, userToUpdate) 时,返回一个id为1的用户对象
        User updatedUser = new User(1L, "alanchanchn", 20, "alan.chan.chn@163.com");
        Mockito.when(userService.updateUser(1L, userToUpdate)).thenReturn(updatedUser);

        // 发送 PUT 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.put("/users/1")
                        .content("{\"name\":\"alanchanchn\",\"age\":20,\"email\":\"alan.chan.chn@163.com\"}")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON))
                // 验证响应状态为200 OK
                .andExpect(MockMvcResultMatchers.status().isOk())
                // 验证响应内容是否符合预期的JSON格式
                .andExpect(MockMvcResultMatchers.content().json("{" +
                        "\"id\":1," +
                        "\"name\":\"alanchanchn\"," +
                        "\"age\":20," +
                        "\"email\":\"alan.chan.chn@163.com\"}"));

        // 测试不存在的用户
        Mockito.when(userService.updateUser(999L, userToUpdate)).thenReturn(null);

        // 发送 PUT 请求并验证响应,期望返回 404 Not Found
        mockMvc.perform(MockMvcRequestBuilders.put("/users/999")
                        .content("{\"name\":\"alanchanchn\",\"age\":20,\"email\":\"alan.chan.chn@163.com\"}")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isNotFound());
    }

    /**
     * 测试删除用户的功能。
     * 该测试方法使用Mockito模拟userService的行为,并使用MockMvc发送HTTP DELETE请求。
     * 测试包括删除存在的用户和删除不存在的用户。
     */
    @Test
    public void testDeleteUser() throws Exception {
        // 模拟 userService 的行为
        Mockito.doNothing().when(userService).deleteUser(1L);

        // 发送 DELETE 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.delete("/users/1")
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isNoContent());

        // 测试不存在的用户
        Mockito.doNothing().when(userService).deleteUser(999L);

        // 发送 DELETE 请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.delete("/users/999")
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isNoContent());
    }
}

五、生成UserController压力测试类

在aicoder的对话框内输入"生成UserController压力测试类"指令,其就可以自动的生成代码了,示例如下。
在这里插入图片描述
更改了生成源码所在的包。

package com.win.test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.win.bean.User;
import com.win.control.UserController;
import com.win.service.UserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
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.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(UserController.class)
public class UserControllerStressTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    private final int threadCount = 1000; // 并发线程数
    private final int requestCount = 10000; // 总请求数

    @BeforeEach
    public void setUp() {
        // 模拟 userService 的行为
        List<User> users = new ArrayList<>();
        users.add(new User(1L, "Alice",18, "alice@example.com"));
        users.add(new User(2L, "Bob",20, "bob@example.com"));
        when(userService.getAllUsers()).thenReturn(users);
        when(userService.getUserById(1L)).thenReturn(Optional.ofNullable(users.get(0)));
        when(userService.getUserById(2L)).thenReturn(Optional.ofNullable(users.get(1)));
    }

    @Test
    public void testGetAllUsersStress() throws Exception {
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        CountDownLatch latch = new CountDownLatch(requestCount);

        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < requestCount; i++) {
            executorService.submit(() -> {
                try {
                    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/users"))
                            .andExpect(status().isOk())
                            .andReturn();

                    successCount.incrementAndGet();
                } catch (Exception e) {
                    failureCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executorService.shutdown();

        System.out.println("成功请求: " + successCount.get());
        System.out.println("失败请求: " + failureCount.get());
    }

    @Test
    public void testGetUserByIdStress() throws Exception {
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        CountDownLatch latch = new CountDownLatch(requestCount);

        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < requestCount; i++) {
            executorService.submit(() -> {
                try {
                    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/users/1"))
                            .andExpect(status().isOk())
                            .andReturn();
                    successCount.incrementAndGet();
                } catch (Exception e) {
                    failureCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executorService.shutdown();

        System.out.println("成功请求: " + successCount.get());
        System.out.println("失败请求: " + failureCount.get());
    }

    @Test
    public void testCreateUserStress() throws Exception {
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        CountDownLatch latch = new CountDownLatch(requestCount);

        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < requestCount; i++) {
            final int index = i; // 将 i 复制为 final 变量
            executorService.submit(() -> {
                try {
                    User user = new User((long) (index + 1000), "User" + index,11, "user" + index + "@example.com");
                    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/users")
                                    .contentType("application/json")
                                    .content(objectMapper.writeValueAsString(user)))
                            .andExpect(status().isOk())
                            .andReturn();
                    successCount.incrementAndGet();
                } catch (Exception e) {
                    failureCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executorService.shutdown();

        System.out.println("成功请求: " + successCount.get());
        System.out.println("失败请求: " + failureCount.get());
    }

    @Test
    public void testUpdateUserStress() throws Exception {
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        CountDownLatch latch = new CountDownLatch(requestCount);

        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < requestCount; i++) {
            final int index = i; // 将 i 复制为 final 变量
            executorService.submit(() -> {
                try {
                    User user = new User((long) (index + 1000), "User" + index, 12,"user" + index + "@example.com");
                    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.put("/users/1")
                                    .contentType("application/json")
                                    .content(objectMapper.writeValueAsString(user)))
                            .andExpect(status().isOk())
                            .andReturn();
                    successCount.incrementAndGet();
                } catch (Exception e) {
                    failureCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executorService.shutdown();

        System.out.println("成功请求: " + successCount.get());
        System.out.println("失败请求: " + failureCount.get());
    }

    @Test
    public void testDeleteUserStress() throws Exception {
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        CountDownLatch latch = new CountDownLatch(requestCount);

        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < requestCount; i++) {
            executorService.submit(() -> {
                try {
                    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.delete("/users/1"))
                            .andExpect(status().isOk())
                            .andReturn();
                    successCount.incrementAndGet();
                } catch (Exception e) {
                    failureCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executorService.shutdown();

        System.out.println("成功请求: " + successCount.get());
        System.out.println("失败请求: " + failureCount.get());
    }

    private ObjectMapper objectMapper = new ObjectMapper();
}

六、验证

正常功能验证,比较容易,不再赘述,基本上不会出错。
单元测试的用例可能需要调整一下,因为其没有有参构造函数。
只要单元测试通过,压力测试结果会通过。
示例如下,本示例使用的覆盖率运行,能看到单元测试的覆盖率。
单元测试覆盖率报告可以导出成html文件,可以自己试一试。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
压力测试,运行的时候会自动记录成功与错误的记录数,以及可以观察一下运行机器的网络、cpu、内存以及硬盘的使用情况,当然如果更专业的压力测试则是使用jmeter等专业的软件。

七、Aicoder其他的功能

1、针对某个方法生成单元测试

在这里插入图片描述
点击单元测试,在AiCoder的面板上就生成了该方法对应的单元测试类,示例如下
在这里插入图片描述

2、针对代码生成注释

示例如下
在这里插入图片描述

3、代码解释

点击代码解释,示例如下
在这里插入图片描述

4、缺陷检测

点击缺陷检测,示例如下
在这里插入图片描述

以上通过AICoder插件,我们可以快速生成SpringBoot技术栈的CRUD代码及其单元测试和压力测试源码。本示例没有生产前端代码,也可以根据需要进行生成,不再赘述。这不仅大大提高了开发效率,还确保了代码的质量和一致性。希望本文能帮助你更好地利用AICoder插件,提升你的开发体验。

本篇文章分为三个部分,即:
通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(一)
通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(二)
通过AI自动生成springboot的CRUD以及单元测试与压力测试源码(完整版)


网站公告

今日签到

点亮在社区的每一天
去签到