目录
1. 插件范围
- 百度“文心一言” Comate
官网详见:https://comate.baidu.com/
- 讯飞“iFlyCode"
官网详见:http://iflycode.xfyun.cn/
- CodeGeeX
官网详见:https://codegeex.cn/zh-CN
- 阿里“通义灵码”
官网详见:https://tongyi.aliyun.com/lingma
2. 初步对比
根据官网文档整理的初步对比。
3. 评测标准和场景
3.1. 标准
-
准确率:低、中、高
-
生成速度:慢、中、快
-
易用性:差、中、友好
3.2. 场景
-
文本排序
-
生成代码
-
生成代码注释
-
代码补全
-
生成单元测试
-
代码纠错
4. 评测结果
先说结论,基于下方评测过程,通义灵码辅助 Java 编码最佳;SQL 及代码纠错方面,可以考虑 iFlyCode。
5. 评测过程
PS:长文警告~
以下用例执行结果均为使用个人版或公测版,均采用云端模型。
由于本人最常用的是 Java,因此代码相关用例以 Java 为例,使用 IDE 为 IDEA 2023.1。
- IDEA 插件版本:
CodeGeeX 2.3.0
Comate 1.13.0
iFlyCode 2.0.0
通义灵码 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. 通义灵码
-
回答
默认使用 mockito+junit 生成单测。
也可以选择 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 秒左右。
-
易用性:差,无快捷操作,只能自己拷贝放到问答框中。
-