国产AI编程辅助插件对比

目录

    1. 插件范围
    1. 初步对比
    1. 评测标准和场景
    • 3.1. 标准
    • 3.2. 场景
    1. 评测结果
    1. 评测过程
    • 5.1. 文本排序
    • 5.2. 生成代码
    • 5.3. 生成代码注释
    • 5.4. 代码补全
    • 5.5. 生成单元测试
    • 5.6. 代码纠错

1. 插件范围

  1. 百度"文心一言" Comate

    官网详见:comate.baidu.com/

  2. 讯飞"iFlyCode"

    官网详见:iflycode.xfyun.cn/

  3. CodeGeeX

    官网详见:codegeex.cn/zh-CN

  4. 阿里"通义灵码"

    官网详见:tongyi.aliyun.com/lingma

2. 初步对比

根据官网文档整理的初步对比。

3. 评测标准和场景

3.1. 标准

  1. 准确率:低、中、高
  2. 生成速度:慢、中、快
  3. 易用性:差、中、友好

3.2. 场景

  • 文本排序
  • 生成代码
  • 生成代码注释
  • 代码补全
  • 生成单元测试
  • 代码纠错

4. 评测结果

先说结论,基于下方评测过程,通义灵码 辅助 Java 编码最佳;SQL 及代码纠错方面,可以考虑 iFlyCode

5. 评测过程

PS:长文警告~

  1. 以下用例执行结果均为使用个人版或公测版,均采用云端模型。

  2. 由于本人最常用的是 Java,因此代码相关用例以 Java 为例,使用 IDE 为 IDEA 2023.1。

  3. IDEA 插件版本:

    1. CodeGeeX 2.3.0
    2. Comate 1.13.0
    3. iFlyCode 2.0.0
    4. 通义灵码 1.0.6

5.1. 文本排序

用例

xml 复制代码
帮我排序下面的XML,要求FieldModuleUpgrader要在UpdateUpgrader后面,并保持每一行内容不变进行结果输出:

<value>com.demo.rdb.upgrade.v1.r2.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r3.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r3.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r2.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r4.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r4.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r5.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r5.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r8.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r7.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r7.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r8.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r6.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r9.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r9.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r10.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r10.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r11.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r11.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r12.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r13.UpdateUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r13.FieldModuleUpgrader</value>
<value>com.demo.rdb.upgrade.v1.r12.FieldModuleUpgrader</value>
5.1.1. iFlyCode
  • 提问
  • 回答
  • 评价

    • 准确率:低,输出格式不对、排序结果也不对;输出结果文本有缺失(可能免费版针对问答大小有限制)。
    • 生成速度:中,15 秒左右。
    • 易用性:中,针对结果无快捷操作。
5.1.2. 通义灵码
  • 提问
  • 回答
  • 评价

    • 准确率:高,输出格式正确、排序结果正确,输出结果无缺失。
    • 生成速度:中,15 秒左右。
    • 易用性:中,针对结果无快捷操作。
5.1.3. CodeGeeX
  • 提问
  • 回答
  • 评价

    • 准确率:低,输出格式正确、排序结果无变化,输出结果无缺失。
    • 生成速度:一般,15 秒左右。
    • 易用性:友好,生成结果有复制快捷操作。
5.1.4. Comate
  • 提问

由于 Comate 没有只有代码生成和代码推荐的功能,没有智能问答,因此本用例使用文心一言 3.5 进行提问。否则会被理解为代码生成,Comate 给出的是生成文本处理的 Java 代码。

  • 回答
  • 评价

    • 准确率:中,输出格式正确、排序结果基本正确,最后几行内容变了,且有一定缺失。
    • 生成速度:中,15 秒左右。
    • 易用性:友好,生成结果有复制快捷操作。

5.2. 生成代码

用例一

kotlin 复制代码
// 以下是一个Java对象,帮我生成oracle的建表脚本,要求使用uuid作为主键,并且需要包含表结构的数据字典脚本:
@Data
@ApiModel(description = "费用规则")
public class FeeRule implements Serializable {
    private static final long serialVersionUID = -7253280007530220138L;
    public static final String TABLE_NAME = "fee_rule";

    @ApiModelProperty(value = "数据标识")
    @Size(max = 38)
    @NotBlank
    private String uuid;
    @ApiModelProperty(value = "规则类型,取值范围:permit-允许,deny-拒绝")
    @NotNull
    private AccessRuleType type;
    @ApiModelProperty(value = "匹配规则")
    @Size(max = 255)
    @NotBlank
    private String matcher;
 @ApiModelProperty(value = "金额")
 @NotNull
 private BigDecimal total;
}

用例二

sql 复制代码
以下是一段oracle建表脚本,根据它生成一个Java类且类属性字段上添加对应的注释说明:

CREATE TABLE fee_rule (
    uuid VARCHAR2(38) NOT NULL,
    type VARCHAR2(10) NOT NULL,
    matcher VARCHAR2(255) NOT NULL,
    total NUMBER(19, 2) NOT NULL,
    PRIMARY KEY (uuid)
);

COMMENT ON TABLE fee_rule IS '费用规则';

COMMENT ON COLUMN fee_rule.uuid IS '数据标识';
COMMENT ON COLUMN fee_rule.type IS '规则类型,取值范围:permit-允许,deny-拒绝';
COMMENT ON COLUMN fee_rule.matcher IS '匹配规则';
COMMENT ON COLUMN fee_rule.total IS '金额';
5.2.1. iFlyCode
  • 回答
typescript 复制代码
# 用例一,生成结果

CREATE TABLE fee_rule (
    uuid VARCHAR2(38) NOT NULL,
    type AccessRuleType NOT NULL,
    matcher VARCHAR2(255) NOT NULL,
    total NUMBER(10, 2) NOT NULL,
    PRIMARY KEY (uuid)
);

COMMENT ON TABLE fee_rule IS '费用规则';

COMMENT ON COLUMN fee_rule.uuid IS '数据标识';
COMMENT ON COLUMN fee_rule.type IS '规则类型,取值范围:permit-允许,deny-拒绝';
COMMENT ON COLUMN fee_rule.matcher IS '匹配规则';
COMMENT ON COLUMN fee_rule.total IS '金额';


# 用例二,生成结果

import java.math.BigDecimal;
import java.util.UUID;

/**
 * 费用规则
 */
public class FeeRule {

    /**
     * 数据标识
     */
    private String uuid;

    /**
     * 规则类型,取值范围:permit-允许,deny-拒绝
     */
    private String type;

    /**
     * 匹配规则
     */
    private String matcher;

    /**
     * 金额
     */
    private BigDecimal total;

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getMatcher() {
        return matcher;
    }

    public void setMatcher(String matcher) {
        this.matcher = matcher;
    }

    public BigDecimal getTotal() {
        return total;
    }

    public void setTotal(BigDecimal total) {
        this.total = total;
    }
}
  • 评价

    • 准确率:高。

      • 用例一,生成脚本和注释基本可直接采用。
      • 用例二,生成的类对象也可直接采用。
    • 生成速度:中,10 秒左右。

    • 易用性:友好。

      • 生成结果有复制、插入、比较、新建文件 4 个快捷操作。
5.2.2. 通义灵码
  • 回答
sql 复制代码
#用例一,生成结果
CREATE TABLE fee_rule (
  uuid VARCHAR2(38) NOT NULL,
  type VARCHAR2(10) NOT NULL,
  matcher VARCHAR2(255) NOT NULL,
  total DECIMAL(19,2) NOT NULL,
  CONSTRAINT fee_rule_pk PRIMARY KEY (uuid)
);

INSERT INTO fee_rule (uuid, type, matcher, total) VALUES ('your-uuid', 'permit', 'your-matcher', 100.00);


#用例二,生成结果
@Data
@ApiModel(description = "费用规则")
public class FeeRule {
    @ApiModelProperty(value = "数据标识", required = true)
    private String uuid;
    @ApiModelProperty(value = "规则类型,取值范围:permit-允许,deny-拒绝", required = true)
    private String type;
    @ApiModelProperty(value = "匹配规则", required = true)
    private String matcher;
    @ApiModelProperty(value = "金额", required = true)
    private BigDecimal total;
}
  • 评价

    • 准确率:

      • 用例一,中。

        • 未生成数据字典脚本。
        • 其中金额更常用 Number 类型来定义。
      • 用例二,高

        • 能结合用例一生成一个简洁合理的对象。
    • 生成速度:快,5 秒左右。

    • 易用性:友好。

      • 方法上有操作按钮选择生成注释,生成结果有复制、插入、新建文件 3 个快捷操作。
5.2.3. CodeGeeX
  • 回答
arduino 复制代码
#用例一,生成结果
CREATE TABLE fee_rule (
  uuid NCHAR(38) DEFAULT '00000000-0000-0000-0000-000000000000' NOT NULL,
  type VARCHAR2(7) NOT NULL,
  matcher VARCHAR2(255) NOT NULL,
  total NUMBER(19,4) NOT NULL,
  PRIMARY KEY (uuid)
);

CREATE SEQUENCE fee_rule_seq
  START WITH 1
  INCREMENT BY 1
  MINVALUE 1
  MAXVALUE CREATE SEQUENCE fee_rule_seq
  START WITH 1
  INCREMENT BY 1
  MINVALUE 1
  MAXVALUE 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999



#用例二,生成结果
import java.math.BigDecimal;

/**
 * 费用规则
 */
public class FeeRule {

    /**
     * 数据标识
     */
    private String uuid;

    /**
     * 规则类型,取值范围:permit-允许,deny-拒绝
     */
    private String type;

    /**
     * 匹配规则
     */
    private String matcher;

    /**
     * 金额
     */
    private BigDecimal total;

    // getters and setters
}
  • 评价

    • 准确率:中。

      • 用例一

        • 字段类型基本是所想要的,除了 uuid。
        • 表结构字典没生成 oracle 自己的添加注释的脚步,而是自己建了个表,且 MAXVALUE 卡死持续输出 9。
      • 用例二

        • 类和属性及属性的注释都生成正确,getters 和 setters 省略了。
    • 生成速度:快,5 秒左右。

    • 易用性:中

      • 生成结果上有复制按钮。
5.2.4. Comate
  • 回答

    • 用例一
  • 用例二
  • 评价

    • 准确率:中。

      • 用例一

        • 字段类型基本是所想要的,除了 uuid。
        • 表结构字典没生成。
      • 用例二

        • 类和属性及属性的注释都生成正确,getters 和 setters 也生成
        • 不足的是,金额的类型给的不对;类属性的注释不太规范。
    • 生成速度:中,15 秒左右。

    • 易用性:中

      • 生成结果上有复制按钮。

5.3. 生成代码注释

用例

typescript 复制代码
生成代码注释

 public static BigDecimal avg(List<Object> list, String propName, int scale, String roundScale) {
      if (CollectionUtils.isEmpty(list)) {
        return BigDecimal.ZERO;
      }

      BigDecimal sum = sum(list, propName);
      return sum.divide(new BigDecimal(list.size()), scale, RoundingMode.valueOf(roundScale));
    }
5.3.1. iFlyCode
  • 提问
  • 回答
  • 评价

    • 准确率:高,生成的注释基本可直接采用。

    • 生成速度:快,5 秒左右。

    • 易用性:友好。

      • 生成结果有复制、插入、比较、新建文件 4 个快捷操作。
      • 也可设置快捷键触发。
      • 也可通过鼠标右键触发。
5.3.2. 通义灵码
  • 提问
  • 回答
  • 评价

    • 准确率:高,生成的注释基本可直接采用。

    • 生成速度:快,5 秒左右。

    • 易用性:友好。

      • 方法上有操作按钮选择生成注释,生成结果有复制、插入、比较、新建文件 4 个快捷操作。
      • 也可设置快捷键触发。
      • 也可通过鼠标右键触发。
5.3.3. CodeGeeX
  • 提问
  • 回答
  • 评价

    • 准确率:中,输出格式不是想要的,有点像代码解释。

    • 生成速度:快,5 秒左右。

    • 易用性:中

      • 选中代码块,通过快捷键或右键触发。
      • 生成结果直接在代码上添加注释,会生成多余的注释。
5.3.4. Comate
  • 回答
  • 评价

    • 准确率:高,注释基本可用。

    • 生成速度:快,5 秒左右。

    • 易用性:中

      • 选中代码块,需要再问答框中点生成注释。
      • 生成结果上有采纳按钮,可以直接插入代码上方。

5.4. 代码补全

用例如下

markdown 复制代码
1. 编写一个Student类,包含uuid、code、name字段。
2. 从一个List<Student>列表中提取uuid列表。
5.4.1. iFlyCode
  • 续写过程
  • 评价

    • 准确率:中。

      • 上述示例中的 get/set 方法级别的续写未能触发。
      • 对代码上下文的识别有待改进。
    • 生成速度:慢,需要停顿等待较长时间。

    • 易用性:友好。

      • 启用插件后自动触发代码续写、或者通过快捷键触发。
      • Esc 取消建议代码,Tab 接受并插入建议代码。
5.4.2. 通义灵码
  • 续写过程
  • 评价

    • 准确率:高,能识别上下文。

    • 生成速度:快,不影响正常的编码。

    • 易用性:友好。

      • 启用插件后自动触发代码续写。
      • Esc 取消建议代码,Tab 接受并插入建议代码。
5.4.3. CodeGeeX
  • 续写过程
  • 评价

    • 准确率:低。

    • 生成速度:慢,示例没录完,卡得不要不要加上准确度低没有往下的必要。

    • 易用性:差

      • 通过快捷键触发、建议结果还得再点下 insert。
5.4.4. Comate
  • 续写过程
  • 评价

    • 准确率:中。

      • 对代码上下文的识别有待改进,不能明确识别 main 函数中 uuids 的赋值意图,需要输入较多上下文才能识别,且生成的建议代码不太理想。
    • 生成速度:快。

    • 易用性:中。

      • 启用插件后自动触发代码续写、或者通过快捷键触发。
      • Esc 取消建议代码,Tab 接受并插入建议代码。
      • 没有多行续写,普通的 getter、setter 都得一行一行进行确认,可能和插件设置的模式有关系。

5.5. 生成单元测试

用例如下

less 复制代码
//生成以下控制器的单元测试代码:

@Api(tags = "测试类")
@RestController
@RequestMapping("/api/student")
public class StudentController {

    @ApiOperation(value = "获取学生")
    @GetMapping(value = "/get")
    public Response<Student> get(@RequestParam(value = "code", required = true) String code) {
        //...
        return Response.success();
    }

    @ApiOperation(value = "创建学生")
    @PostMapping(value = "/create")
    public Response<Void> create(@RequestBody Student student) {
        //...
        return Response.success();
    }

    @ApiOperation(value = "编辑学生")
    @PostMapping(value = "/modify")
    public Response<Void> modify(@RequestBody Student student) {
        //...
        return Response.success();
    }

    @ApiOperation(value = "删除学生")
    @PostMapping(value = "/delete")
    public Response<Void> delete(@RequestBody Student student) {
        //...
        return Response.success();
    }
}
5.5.1. iFlyCode
  • 回答
java 复制代码
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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
public class StudentControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testGet() throws Exception {
        String code = "123456";
        mockMvc.perform(get("/api/student/get")
                .param("code", code))
                .andExpect(status().isOk());
    }

    @Test
    public void testCreate() throws Exception {
        Student student = new Student();
        // Set student properties here
        mockMvc.perform(post("/api/student/create")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json(student)))
                .andExpect(status().isOk());
    }

    @Test
    public void testModify() throws Exception {
        Student student = new Student();
        // Set student properties here
        mockMvc.perform(post("/api/student/modify")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json(student)))
                .andExpect(status().isOk());
    }

    @Test
    public void testDelete() throws Exception {
        Student student = new Student();
        // Set student properties here
        mockMvc.perform(post("/api/student/delete")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json(student)))
                .andExpect(status().isOk());
    }

    @Test
    public void testGetMissingParam() throws Exception {
        mockMvc.perform(get("/api/student/get"))
                .andExpect(status().is4xxClientError());
    }

    @Test
    public void testCreateMissingParam() throws Exception {
        Student student = new Student();
        // Remove required property here
        mockMvc.perform(post("/api/student/create")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json(student)))
                .andExpect(status().is4xxClientError());
    }

    @Test
    public void testModifyMissingParam() throws Exception {
        Student student = new Student();
        // Remove required property here
        mockMvc.perform(post("/api/student/modify")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json(student)))
                .andExpect(status().is4xxClientError());
    }

    @Test
    public void testDeleteMissingParam() throws Exception {
        mockMvc.perform(post("/api/student/delete")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json(new Student())))
                .andExpect(status().is4xxClientError());
    }
}
  • 评价

    • 准确率:高

      • 生成的建议代码基本可用,只需补充 json 方法、执行入口类声明。
    • 生成速度:慢,20 秒左右。

    • 易用性:友好。

      • 生成结果有复制、插入、比较、新建文件 4 个快捷操作。
      • 也可设置快捷键触发。
      • 也可通过鼠标右键触发。
5.5.2. 通义灵码
  • 回答
  1. 默认使用 mockito+junit 生成单测。
  2. 也可以选择 Sprint Test 库生成。
less 复制代码
//Mockito框架生成的
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.ResponseEntity;

import static org.mockito.Mockito.*;

public class StudentControllerTest {

    @Mock
    private StudentService studentService;

    @InjectMocks
    private StudentController studentController;

    @BeforeEach
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGet() {
        String code = "123456";
        Student student = new Student();
        when(studentService.getByCode(code)).thenReturn(student);

        ResponseEntity<Response<Student>> response = studentController.get(code);
        Assertions.assertEquals(ResponseStatus.SUCCESS.getStatusCode(), response.getStatusCode());
        Assertions.assertEquals(student, response.getBody().getData());
    }

    @Test
    public void testCreate() {
        Student student = new Student();
        when(studentService.create(student)).thenReturn(ResponseStatus.SUCCESS);

        ResponseEntity<Response<Void>> response = studentController.create(student);
        Assertions.assertEquals(ResponseStatus.SUCCESS.getStatusCode(), response.getStatusCode());
        Assertions.assertNull(response.getBody().getData());
    }

    @Test
    public void testModify() {
        Student student = new Student();
        when(studentService.modify(student)).thenReturn(ResponseStatus.SUCCESS);

        ResponseEntity<Response<Void>> response = studentController.modify(student);
        Assertions.assertEquals(ResponseStatus.SUCCESS.getStatusCode(), response.getStatusCode());
        Assertions.assertNull(response.getBody().getData());
    }

    @Test
    public void testDelete() {
        Student student = new Student();
        when(studentService.delete(student)).thenReturn(ResponseStatus.SUCCESS);

        ResponseEntity<Response<Void>> response = studentController.delete(student);
        Assertions.assertEquals(ResponseStatus.SUCCESS.getStatusCode(), response.getStatusCode());
        Assertions.assertNull(response.getBody().getData());
    }
}

//SpringTest生成的
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentControllerTest {

    @Autowired
    private WebApplicationContext context;

    @Test
    public void getTest() {
        // Mock request parameters
        MockHttpServletRequestBuilder getBuilder = MockMvcRequestBuilders.get("/api/student/get")
                .param("code", "123456");

        // Perform the GET request
        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        mockMvc.perform(getBuilder)
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultMatchers.write(outputMessage));

        // Verify the response
        String responseBody = outputMessage.getContentAsString();
        Response<Student> response = objectMapper.readValue(responseBody, ResponseStudent.class);
        Assertions.assertEquals(HttpStatus.OK, response.getStatus());
        Assertions.assertNotNull(response.getData());
        // Assert other properties of the response here
    }

    @Test
    public void createTest() {
        // Mock request body
        Student student = new Student();
        // Set properties of the student object

        // Perform the POST request
        MockHttpServletRequestBuilder postBuilder = MockMvcRequestBuilders.post("/api/student/create")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(student));

        // Perform the POST request
        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        mockMvc.perform(postBuilder)
                .andExpect(status().isCreated())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultMatchers.write(outputMessage));

        // Verify the response
        String responseBody = outputMessage.getContentAsString();
        Response<Void> response = objectMapper.readValue(responseBody, ResponseVoid.class);
        Assertions.assertEquals(HttpStatus.CREATED, response.getStatus());
        Assertions.assertNull(response.getData());
        // Assert other properties of the response here
    }

    @Test
    public void modifyTest() {
        // Mock request body
        Student student = new Student();
        // Set properties of the student object

        // Perform the POST request
        MockHttpServletRequestBuilder postBuilder = MockMvcRequestBuilders.post("/api/student/modify")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(student));

        // Perform the POST request
        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        mockMvc.perform(postBuilder)
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultMatchers.write(outputMessage));

        // Verify the response
        String responseBody = outputMessage.getContentAsString();
        Response<Void> response = objectMapper.readValue(responseBody, ResponseVoid.class);
        Assertions.assertEquals(HttpStatus.OK, response.getStatus());
        Assertions.assertNull(response.getData());
        // Assert other properties of the response here
    }

    @Test
    public void deleteTest() {
        // Mock request body
        Student student = new Student();
        // Set properties of the student object

        // Perform the POST request
        MockHttpServletRequestBuilder postBuilder = MockMvcRequestBuilders.post("/api/student/delete")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(student));

        // Perform the POST request
        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        mockMvc.perform(postBuilder)
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultMatchers.write(outputMessage));

        // Verify the response
        String responseBody = outputMessage.getContentAsString();
        Response<Void> response = objectMapper.readValue(responseBody, ResponseVoid.class);
        Assertions.assertEquals(HttpStatus.OK, response.getStatus());
        Assertions.assertNull(response.getData());
        // Assert other properties of the response here
    }
}
  • 评价

    • 准确率:中~高。

      • mockito 生成的结果不理想,基本不可用。
      • SpringTest 的生成的结构比 iFlyCode 多了 response 校验,但缺少 import 包,同时部分异常、注解、变量没有声明;要跑起来比较费劲。
    • 生成速度:快,10~15 秒左右。

    • 易用性:友好。

      • 可设置快捷键或右键选择触发生成单元测试。
      • 生成结果有插入、复制、新建快捷操作按钮。
      • 生成结果可选择单测的框架生成。
5.5.3. CodeGeeX
  • 回答
java 复制代码
import com.example.demo.controller.StudentController;
import com.example.demo.entity.Student;
import com.example.demo.response.Response;
import com.example.demo.response.StudentResponse;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcSetup;

import static org.springframework.test.web.servlet.request.RequestMethod.GET;
import static org.springframework.test.web.servlet.request.RequestMethod.POST;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

public class StudentControllerTest {

    private MockMvc mockMvc;

    @Test
    public void testGet() throws Exception {
        // Prepare test data
        String code = "123";

        // Create mock request and response
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setMethod(GET.toUpperCase());
        request.addParameter("code", code);

        MockHttpServletResponse response = new MockHttpServletResponse();

        // Prepare mock controller instance
        StudentController studentController = new StudentController();

        // Configure mock MVC
        MockMvcSetup mockMvcSetup = mockMvcSetup()
                .andController(studentController)
                .andRequest(request)
                .andResponse(response);

        // Execute test
        mockMvc.perform(mockMvcSetup)
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(code));
    }

    @Test
    public void testCreate() throws Exception {
        // Prepare test data
        Student student = new Student();
        student.setCode("123");
        student.setName("John Doe");

        // Create mock request and response
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setMethod(POST.toUpperCase());
        request.addHeader("Content-Type", "application/json");
        request.setContentType("application/json");
        request.setCharacterEncoding("UTF-8");
        request.getWriter().write(student.toString());
        request.getWriter().flush();
        request.getWriter().close();

        MockHttpServletResponse response = new MockHttpServletResponse();

        // Prepare mock controller instance
        StudentController studentController = new StudentController();

        // Configure mock MVC
        MockMvcSetup mockMvcSetup = mockMvcSetup()
                .andController(studentController)
                .andRequest(request)
  • 评价

    • 准确率:差。

      • 内容输出不全,可能免费版有限制。
      • 生成代码不够友好,部分常量写死。
      • 生成代码难以使用。
    • 生成速度:快,10 秒左右。

    • 易用性:中

      • 选中代码块,通过智能问答框输入"生成单元测试"。
      • 生成结果有复制按钮。
5.5.4. Comate
  • 回答
java 复制代码
package com.test.ai;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
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.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private StudentService studentService;

    @Test
    public void get() throws Exception {
        Mockito.when(studentService.get(Mockito.anyString())).thenReturn(new Student());
        RequestBuilder builder = (RequestBuilder) new RequestBuilder()
                .setRequest(TestClient.httpRequest("/get?code=123", "GET"))
                .setMediaType(MediaType.APPLICATION_JSON);
        ResponseEntity<Response<Student>> response = TestClient.sendRequest(mvc, builder, new TypeReference<Response<Student>>() {});
        Assertions.assertNotNull(response);
        Assertions.assertEquals(200, response.getStatusCode().value());
    }
}
  • 评价

    • 准确率:低。

      • 只生成了 get 方法,没有 service 也给生成了 service 相关代码。
      • 生成的结果需要费大力气改动才能跑起来。
    • 生成速度:快,8 秒左右。

    • 易用性:中。

      • 有采纳的快捷按钮操作,可以直接在 test 目录下自动生成单测类。

5.6. 代码纠错

用例如下

typescript 复制代码
 //下面代码存在bug吗?
 public static BigDecimal avg(List<Object> list, String propName, int scale, String roundScale) {
      if (CollectionUtils.isEmpty(list)) {
        return BigDecimal.ZERO;
      }

      BigDecimal sum = sum(list, propName);
      return sum.divide(new BigDecimal(list.size()), scale, RoundingMode.valueOf(roundScale));
    }
5.6.1. iFlyCode
  • 提问
  • 回答
typescript 复制代码
//由于结果展示不友好,以下为复制出来后的修复结果
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.apache.commons.collections4.CollectionUtils;
import java.util.List;

public class Main {
    public static BigDecimal sum(List<Object> list, String propName) {
        BigDecimal sum = BigDecimal.ZERO;
        for (Object obj : list) {
            try {
                // Assuming propName is a field in the object and it's type is BigDecimal
                Field field = obj.getClass().getDeclaredField(propName);
                field.setAccessible(true);
                sum = sum.add(new BigDecimal(field.get(obj).toString()));
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return sum;
    }

    public static BigDecimal avg(List<Object> list, String propName, int scale, String roundScale) {
        if (CollectionUtils.isEmpty(list)) {
            return BigDecimal.ZERO;
        }

        BigDecimal sum = sum(list, propName);
        RoundingMode roundingMode;
        try {
            roundingMode = RoundingMode.valueOf(roundScale);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid rounding mode: " + roundScale, e);
        }
        return sum.divide(new BigDecimal(list.size()), scale, roundingMode);
    }
}
  • 评价

    • 准确率:高,生成的建议代码基本可用。

    • 生成速度:中,15 秒左右。

    • 易用性:友好。

      • 生成结果有复制、插入、比较、新建文件 4 个快捷操作。
      • 也可设置快捷键触发。
      • 也可通过鼠标右键触发。
5.6.2. 通义灵码
  • 回答
  • 评价

    • 准确率:低。
    • 生成速度:快,5 秒左右。
    • 易用性:差,无快捷操作,只能自己拷贝放到问答框中。
5.6.3. CodeGeeX
  • 提问
  • 回答
  • 评价

    • 准确率:中,如果 sum 没处理好返回值,确实可能存在其描述的 bug。

    • 生成速度:快,5 秒左右。

    • 易用性:中

      • 选中代码块,通过右键或快捷键触发智能问答;或这自行拷贝到问答框中。
      • 纠错结果提供拷贝按钮。
5.6.4. Comate
  • 回答
  • 评价

    • 准确率:低,结果和通义灵码类似,处理方式还略有不如。
    • 生成速度:快,5 秒左右。
    • 易用性:差,无快捷操作,只能自己拷贝放到问答框中。
相关推荐
咖啡啡不加糖1 小时前
Redis大key产生、排查与优化实践
java·数据库·redis·后端·缓存
大鸡腿同学1 小时前
纳瓦尔宝典
后端
2302_809798323 小时前
【JavaWeb】Docker项目部署
java·运维·后端·青少年编程·docker·容器
zhojiew3 小时前
关于akka官方quickstart示例程序(scala)的记录
后端·scala
sclibingqing3 小时前
SpringBoot项目接口集中测试方法及实现
java·spring boot·后端
JohnYan4 小时前
Bun技术评估 - 03 HTTP Server
javascript·后端·bun
周末程序猿5 小时前
Linux高性能网络编程十谈|C++11实现22种高并发模型
后端·面试
ZHOU_WUYI5 小时前
Flask与Celery 项目应用(shared_task使用)
后端·python·flask
冒泡的肥皂5 小时前
强大的ANTLR4语法解析器入门demo
后端·搜索引擎·编程语言