跳到主要内容
Copilot、Cursor、JetBrains 实战四场景:从测试到 CRUD 的关键写法 | 极客日志
编程语言 VScode Node.js AI java
Copilot、Cursor、JetBrains 实战四场景:从测试到 CRUD 的关键写法 围绕生成测试、解释遗留代码、代码重构和生成 CRUD 四类场景,对比 GitHub Copilot、Cursor 和 JetBrains AI Assistant 的实际操作差异。强调提示词的写法是关键:测试时必须明确列出边界用例,解释代码需引导深入分析,重构前务必有测试兜底,生成 CRUD 要精确指定技术栈。结合各工具特点给出具体示例和注意点,指出 AI 处理重复工作,但业务逻辑与质量审查仍需开发者主导。
Copilot、Cursor、JetBrains 实战四场景:从测试到 CRUD 的关键写法
这三款 AI 编程助手——GitHub Copilot、Cursor 和 JetBrains AI Assistant——用熟了都能扛掉不少重复工作,但各自擅长的场景不太一样。下面四个场景是我在实际项目里最常碰到的,每个工具的操作要点和坑也一并说清楚。提示词怎么写、哪些事得自己兜底,直接影响生成质量。
一、生成测试用例:覆盖边界是关键
让 AI 写测试,最容易踩的坑就是边界覆盖不全。你得在提示里把极端情况列清楚,它才会认真处理。下面分工具说。
GitHub Copilot
写测试时,Copilot 靠注释来理解意图。比如 divide 函数,只写 # test divide,它大概率只生成正常除法。在注释里明确列出边界场景——除数为 0、极小浮点、被除数为 0——生成的质量就明显提升。
def divide (a, b ):
if b == 0 :
raise ValueError("Cannot divide by zero" )
return a / b
def test_divide ():
assert divide(10 , 2 ) == 5.0
try :
divide(10 , 0 )
assert False , "Expected ValueError"
except ValueError:
pass
assert abs (divide(1 , 1e-10 ) - 1e10 ) < 1e-5
assert divide(0 , 5 ) == 0.0
如果生成还不全,就继续补注释,比如再加 ,Copilot 会接着补上。
# 测试负数除法
JetBrains AI Assistant 在 PyCharm 或 IntelliJ 里,右键点函数选 AI Assistant → Generate Tests ,对话框里一定要把要求写死。默认生成往往只覆盖最常规的路径,不加这步很容易漏掉异常和极值。
生成 JUnit 5 测试类,覆盖以下场景:
正常整数除法(10/2)
除数为 0(期望抛出 ArithmeticException)
除数为极小浮点数(1e-10)
被除数为最大值(Double.MAX_VALUE)
除数为负数(-2)
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void testNormalDivision () {
assertEquals(5.0 , Calculator.divide(10 , 2 ));
}
@Test
void testDivideByZero () {
assertThrows(ArithmeticException.class, () -> Calculator.divide(10 , 0 ));
}
@Test
void testDivideByVerySmallNumber () {
assertEquals(1e10 , Calculator.divide(1 , 1e-10 ), 1e-5 );
}
}
业务特有的边界(比如年龄不能为负)它猜不到,生成后得自己补上。
Cursor Cursor 的聊天面板很适合自然语言交互。直接说明方法名、框架和边界要求,它会输出完整测试套件。例如:
为 UserService.createUser 方法生成 Jest 测试,用例要求:
正常创建(姓名、邮箱有效)
邮箱格式错误(应抛出 ValidationError)
姓名超过 50 字符(边界测试)
空对象传入(边界测试)
生成结果可以直接运行,但需要注意:Cursor 有时会使用过时的断言风格,如果与项目配置不符,手动改一下就好。
import { createUser } from './userService' ;
test ('正常创建用户' , () => {
const user = createUser ({ name : '张三' , email : '[email protected] ' });
expect (user.id ).toBeDefined ();
});
test ('邮箱格式错误' , () => {
expect (() => createUser ({ name : '李四' , email : 'invalid' }))
.toThrow ('ValidationError' );
});
test ('姓名超过 50 字符' , () => {
const longName = 'a' .repeat (51 );
expect (() => createUser ({ name : longName, email : '[email protected] ' }))
.toThrow ('Name too long' );
});
二、解释遗留代码:别只问'这是啥' 遗留代码通常没注释、逻辑扭成一团。简单让 AI'解释这段代码',得到的往往是表面翻译,价值不大。得引导它做具体分析。
GitHub Copilot 结构化注释能大幅提升解释深度。在代码上方加一段类似这样的说明,Copilot 就会按点回答:
def legacy_calculator (x, y, op ):
if op == 'add' :
return x + y
elif op == 'sub' :
if x < y:
return 0 - (x - y)
return x - y
else :
return None
它会详细指出 0 - (x - y) 实际就是 y - x,很可能是历史补丁的残留;还会提醒浮点比较的风险。这种提示远比自己盯着代码猜高效。
JetBrains AI Assistant 选中代码块,右键选择 Explain Code ,默认给出的是基础解释。想挖深一点,得在面板里追加提问,比如:
请分析该函数的时间复杂度,并指出潜在性能瓶颈。同时说明如果要重构为异步逻辑,哪些部分需要修改。
时间复杂度 :O(n²),因为有两层嵌套循环。
瓶颈点 :内层循环可改用 Map 查找降至 O(n)。
重构注意 :第 20 行的 data.get(i) 可能返回 null,异步化前需统一处理。
Cursor Cursor 支持多轮对话,特别适合拆解复杂逻辑。我习惯这样问:
第一轮:用一句话总结该函数的目的。
第二轮:用 Mermaid 画出流程图。
第三轮:flag 变量什么时候被重置?生命周期是怎样的?
解释结果还能直接导出为 Markdown 文档,团队分享很方便。
三、代码重构与优化:先有测试,再信任 AI AI 重构常犯两个毛病:过度优化(删掉重要日志或注释),或悄悄改变行为。我的原则是:没有测试就不重构,生成后立刻跑测试看行为是否一致。
GitHub Copilot 在代码上方写目标明确的注释,Copilot 会按指令改。比如:
public List<User> getActiveUsers (List<User> allUsers) {
List<User> active = new ArrayList <>();
for (User u : allUsers) {
if (u.getStatus().equals("active" )) {
active.add(u);
}
}
String sql = "SELECT * FROM users WHERE status = 'active'" ;
return active;
}
生成的代码会提取 SQL 方法、用 Stream 筛选,并加上 null 检查:
public List<User> getActiveUsers (List<User> allUsers) {
if (allUsers == null ) return Collections.emptyList();
String activeSql = getActiveUsersSql();
return allUsers.stream()
.filter(u -> "active" .equals(u.getStatus()))
.collect(Collectors.toList());
}
private String getActiveUsersSql () {
return "SELECT * FROM users WHERE status = 'active'" ;
}
注意:Stream 在大数据量下不一定比 for-loop 快,如果性能敏感,最好做个对比。
JetBrains AI Assistant 选中代码,右键 → Refactor This Code ,在提示框里把重构目标写具体:
目标:
将循环替换为 Java Stream
提取 validateInput 方法,处理 null 和空集合
移除未使用的变量 legacyFlag
保持原有异常抛出逻辑
AI 会生成 diff 预览,确认后再点 Apply 直接修改。但一定要先备份或提交到 Git,它的撤销机制有时不够利索。
Cursor 光标建议在临时分支上操作。在 AI Chat 输入:
请重构 processData 函数:
将 for 循环改为 Promise.all(异步化)
使用 TypeScript 类型注解
限制并发数为 5(避免 DDoS)
输出重构前后对比
它会给出带类型的重构版本,并且标注限制并发的实现(比如嵌入 p-limit):
async function processData (items ) {
const results = [];
for (const item of items) {
results.push (await fetchData (item));
}
return results;
}
async function processData<T>(items : T[]): Promise <ReturnType <typeof fetchData>[]> {
const limit = pLimit (5 );
const limitedFetch = items.map (item => () => fetchData (item));
return await Promise .all (limitedFetch.map (fn => limit (fn)));
}
四、用自然语言生成 CRUD 脚手架 生成 CRUD 时,AI 最怕的是把框架搞错。提示里必须声明技术栈和具体约束,否则它可能给你 Django 版本却要求 Spring Boot。我的习惯是:先生成最基础的增删改查,通过测试后再一层层加业务校验和权限。
GitHub Copilot 新建文件,用注释描述需求,Copilot 能实时补全。比如 FastAPI + SQLAlchemy 的例子:
Copilot 会生成完整的模型、Pydantic 校验和路由。拿到代码后,再手动补上用户名唯一性检查这样的业务逻辑:
@app.post("/users/" , response_model=User )
def create_user (user: UserCreate, db: Session = Depends(get_db ) ):
existing = db.query(UserModel).filter (UserModel.username == user.username).first()
if existing:
raise HTTPException(status_code=400 , detail="用户名已存在" )
db_user = UserModel(username=user.username, email=user.email)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
JetBrains AI Assistant 在 Spring Boot 项目中,右键选 Generate Code from Description ,写明要求:
使用 Spring Boot + JPA 生成 Product 资源的 CRUD REST API。
数据库表:products(id, name, price, stock, created_at)
要求:使用 Lombok 简化代码,添加全局异常处理,Swagger 文档支持,不生成测试代码。
它会自动生成实体类、Repository、Controller 和异常处理器骨架。之后再往 updateProduct 里加库存不能为负的校验:
if (dto.getStock() != null && dto.getStock() < 0 ) {
throw new IllegalArgumentException ("库存不能为负数" );
}
Cursor 可以把需求写成 prompt.txt 放在项目根目录,然后让 AI 生成代码。例如 Node.js + Express + Mongoose 的 Category 模块:
项目:Node.js + Express + Mongoose
实体:Category(分类)
字段:_id, name, description, is_active, created_at
需求:
- 生成完整 CRUD 路由(/api/categories)
- 使用 async/await
- 添加分页查询(页码、每页数量)
- 返回格式:{ code: 0, data: {...}, msg: '成功' }
- 不包含认证
Cursor 会按 MVC 结构生成文件。拿到基础代码后,再在 updateCategory 里插入权限判断(假设已有认证中间件):
exports .updateCategory = async (req, res) => {
if (!req.user || req.user .role !== 'admin' ) {
return res.status (403 ).json ({ code : -1 , msg : '无权限操作' });
}
};
几点实操心得
明确技术栈是第一原则
每次生成前,把框架、语言、版本写清楚。AI 默认常用版本可能偏旧,不写就会给你惊喜。
迭代,别指望一次完美
先让 AI 出基础版 → 测试 → 补提示 → 重新生成。三四个来回很正常。
测试自己补
AI 生成的代码即使通过了简单用例,边界 bug 也常有。每个 CRUD 操作都得有自己的边界测试,参考第一节的方法。
审查不能省
像审查同事代码一样查 AI 输出:SQL 注入风险、权限缺失、异常处理是否合理。
Prompt 存下来
把有效的提示词记录到项目 PROMPTS.md,团队后来者直接复用,效率高很多。
这三个工具,Copilot 擅长实时补全和逐步引导修改,Cursor 的交互式提问在拆解遗留代码或复杂逻辑时很舒服,JetBrains 则强在 IDE 深度集成,一键生成测试、重构和脚手架最省事。组合使用效果更好,比如用 JetBrains 生成基础代码,切到 Copilot 优化注释和片段,最后在 Cursor 里生成测试和文档。
说到底,AI 处理的是重复性、低价值的搭建工作,业务逻辑、架构决策和最终的质量兜底,还是得留给自己。
相关免费在线工具 RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online