国产AI编程辅助插件对比

目录

1. 插件范围

2. 初步对比

3. 评测标准和场景

3.1. 标准

3.2. 场景

4. 评测结果

5. 评测过程

5.1. 文本排序

5.2. 生成代码

5.3. 生成代码注释

5.4. 代码补全

5.5. 生成单元测试

5.6. 代码纠错


1. 插件范围

  1. 百度“文心一言” Comate

    官网详见:https://comate.baidu.com/

  2. 讯飞“iFlyCode"

    官网详见:http://iflycode.xfyun.cn/

  3. CodeGeeX

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

  4. 阿里“通义灵码”

    官网详见:https://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,要求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. 生成代码

用例一

// 以下是一个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;
}

用例二

以下是一段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
  • 回答

# 用例一,生成结果

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. 通义灵码
  • 回答

#用例一,生成结果
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
  • 回答

#用例一,生成结果
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. 生成代码注释

用例

生成代码注释

 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. 代码补全

用例如下

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. 生成单元测试

用例如下

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

@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
  • 回答

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 库生成。

//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
  • 回答

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
  • 回答

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. 代码纠错

用例如下

 //下面代码存在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
  • 提问

  • 回答

//由于结果展示不友好,以下为复制出来后的修复结果
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 秒左右。

    • 易用性:差,无快捷操作,只能自己拷贝放到问答框中。

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值