为什么要用AI写单测
这个问题分两点来说,第一是为什么要写单测,第二是为什么要用AI。
先来说为什么写单测,这很简单,咱们项目或许说咱们前端团队有公共模块,包含有组件类型、工具函数类型、hooks类型等,咱们最大也是重点的项目,使用的技能栈是 React,因而这儿说的 hooks 是指 react hooks,随着前端队伍壮大,开端考虑用开源的思路来维护这些代码,那么单测便是正规化的其间很重要一环。
至于第二点,主要是考虑提效,所以做一次测验,项目里有祖传的 Jest 装备,可是具体需求什么依靠,需求依据所写的单测是什么类型,以及其时技能栈是什么版别,这就有必定建立的学习成本,因而,本次设定为从0到1建立 Jest 环境到跑通 AI 所写的用例。
使用的IDE
Cursor,版别0.2.5:
AI模型:
不是GPT-4
想要一直使用中文对话,能够这样装备:
点右上角的图标,翻开辅佐侧栏,点 MORE,然后告诉他,一直使用中文回答,这个装备现在只能有一条。
比如
Github仓库地址:
github.com/bdlite/hook…
用来做比如的分支:
preview/previous
感兴趣的话能够一边 clone 下来,用 Cursor 翻开文件夹,然后一边跟着操作。
开端
仓库都有什么
- 有从咱们实际项目里剥离出的工程类装备文件,例如 .babelIrc、.gitignore、jest.config.js,装备项也只留取需求的
- package.json 是使用 npm init 初始化的,生成进程略,触及到要添加的包后文也会有提及
- src 目录便是放源码了,es 目录是编译为 esModules 的制品途径,发布到 npm 用的是这个目录,因而单测也引证的这个目录
- coverage 目录是 jest 自动生成的报告结果
- __tests__ 目录是空的
看下祖传的jest.config.js
全选整段文件内容,会出现两个选项(这儿的 Cursor 界面还有点小小的 bug),一个是 Edit,一个是 Chat,不同的是,Edit 能够直接帮你生成新代码或许改代码,Chat 是基于这段代码你能够问些问题,但不在编辑框内生成代码。
我这儿想让它直接帮我生成注释,便于辅佐剖析一下这个装备有哪些不妥(懒得看官方文档的这儿集合
生成的是英文,先 Reject,看来辅佐侧栏里边装备的在代码编辑框里并不共用,从头调整 Prompt 输入:
这一次 Accept:
这么读起来,尽管是祖传的装备,似乎看不出什么毛病,当然为了制造比如,其实是有所调整的,至少项目里的途径配的没问题,因而这儿的装备也是模拟了一下,途径也没问题,基于此,咱们开端让Cursor写用例,然后跑起来看看。
看下源码
为了确保环境建立及后续发布流程比较靠谱,咱们先 check 一下哪些是 dependencies,哪些是 devDependencies 和 peerDependencies:
- ‘react’ 显然不能跟着打包,放 peer
- ‘query-string’ 这种库仍是要谨慎点,放 depend
去 package.json 确认一下是否放对了
这儿有个问题,没有指定 react ,因而我让“助理”帮我加一下:
accept 之后多了个花括号,手动删吧,谁让它仍是个孩子啊。
好戏开场
我这是其时翻开 package.json 的状况下在侧边栏问的,再试试翻开 useSearch.js 的状况下问问:
公然其时翻开的文件便是提问的上文,能够见到上一个其实并不是我源码完成的内容,我估计是从其他地方找来的答案,公然是一本正经也能胡说八道呀
行,这儿的计划给得仍是蛮全面的,比方说教你加哪些依靠,手把手教你创建文件,可惜的是,它其实并不能读取整个工程,跨文件去理解上下文,因而它不知道的是,我配了 jest 去读 __tests__ 下的文件
review 下用例
依上文,用例只有三个,只看代码不履行的话,似乎做到了最小的功能检验
再换个思路试试
从以上两个提问的答案来看,看懂代码是没问题的,也能指出里边有问题的点,表现不错
基本上符合源码触及的几个场景,不过,依据我的判别,似乎还有点问题:
-
没有开场处的验证 hooks 返回类型的用例
-
此处的第二个用例:假如key不是字符串或许value是null,那么函数不会进行任何操作
- 看到这个才发现,源码里存在着 bug,为什么在问它有没有 bug 的时分没反应过来,因为其时还没做比如的时分问过,回答是没什么问题,看来这孩子也是变聪明了,也可能是其时的上下文有差异,导致孩子只管夸,没理性思考,是的,我会去问写得好不好,哈哈
- bug 便是,其实咱们是希望 value是null 或许 undefined,那么会清掉 search 中对应的 key
其他问题不大,最多想起来什么场景补充一下就好
run 一下看
按上文说到的,在 __tests__ 目录下创建 useSearch.test.js 文件,然后把方才的代码仿制进去,可是引证 useSearch 函数的途径略微改一下:
import { useSearch } from 'es/useSearch';
装置 jest 各种依靠
依据提示,最省事儿的办法,从头装置,并在指令后加上 –legacy-peer-deps
npm install --save-dev jest @babel/core @babel/preset-env @babel/preset-react babel-jest identity-obj-proxy react-test-renderer --legacy-peer-deps
履行 test 指令
该指令的装备同样是祖传的
在终端里履行:
npm run test
还得装依靠
OK~装它!
一步一足迹啊,持续装它!
再履行一次,这次是 Module ts-jest in the transform option was not found.
ts-jest 装完了,然后再 run test
做个比如不容易,那就持续装!
可是这儿我会都装到 devDependencies,再 run
翻开引荐的链接
OK,试一下 use react-test-renderer
装 react,装到 devDependencies,再 run
履行成功,祖传的指令写得倒没啥问题,上“链接”:
npm install --save-dev cross-env jest-environment-jsdom ts-jest react-dom react-test-renderer react
剖析用例没经过的原因
选中这个用例,问下“助理”
点 Edit
好吧,怪我给的自由太过火,从头调整下
accept 然后跑看看,经过了,不截图了,看下一个
这个问题原因一致,但其实,这个不符合咱们对这个 hooks 的期待,用过错的源码逻辑来生成过错的用例了属于是,直接改
why?
看下提示中的 Received 就知道了
- 第三个用例因为源码确实存在这个 bug,这现在来说是按照“预期” failed了
- 第四个为什么就不对了,第一次能跑出结果的时分不是经过了么,其实跟第二个用例的问题一样,不谨慎导致的,这儿面每一个用例中的 window 并不处于块级效果域,像第二个一样改过来就好了
让它改第四个
就剩下第三个用例没跑通了
改源码中的 bug
改源码,选中源码,然后 Edit
我哭死,感觉它不会写代码,又或许是我的锅?
算了算了,先手动改改
import { useCallback } from 'react'
import queryString from 'query-string'
export function useSearch() {
const searchList = [] // 同一组件接连调用的缓冲区
const getSearch = useCallback(() => queryString.parse(window.location.search), [ window.location.search ])
const setSearch = useCallback((key, value = null) => {
const search = getSearch()
if (search[key] === `${value}` || typeof key !=='string') return
searchList.push({ [key]: value })
const nextSearchData = { ...search, ...searchList.reduce((before, current) => ({ ...before, ...current }), {}) }
const nextSearch = queryString.stringify(nextSearchData, { skipNull: true })
window.history.replaceState(queryString.parse(nextSearch), '', `?${nextSearch}`)
}, [ getSearch, window.history ])
return { getSearch, setSearch }
}
这儿改的是 src 目录下的文件,咱们测的时分引证的是 es 的文件,因而在 package.json 的 script 里改下
从头履行
4个用例终于跑通了,yes!
使用 Prompt 供给上下文修复报错
再把之前说到的类型验证加上
it('should return an object with getSearch and setSearch functions', () => {
const { getSearch, setSearch } = useSearch();
expect(typeof getSearch).toBe('function');
expect(typeof setSearch).toBe('function');
});
run 后报错:
用侧边栏的 Chat 求救一下
选顶用例,Edit
喜提大结局,撒花~
总结
本次实验操作途径
- 喂源码
- 生成用例
- 依据提示搭环境
- review 用例和源码
- 找出问题并修复
- 丰富用例
- 遇到报错
- 喂过错信息
- 依据信息修复
- 跑通
假如没有喂给比较合适的上下文,可能会得不到精确的答案。
假如给的描绘不行精准,例如我让它修复源码的 bug 就不尽如人意,信任给出足够多,足够精准的信息,应该仍是能够的,或许你代码的结构上原本就有点问题,AI 不见得能够懂你希望连结构上的问题一同都能优化的心思,限于本文不是生成代码,而是用例,这一块没有展开来做测验。
工程领域的希望
这个比如建立 Jest 的进程仍是比较顺利的,我在咱们的业务项目里建立,过错信息很难解,比如中的步骤其实是带有一点天主视角的,包含里边其完成已自带了装备文件。
现在发现 AI 并不能阅读整个工程的装备、某个指定目录下的文件,据我了解,必须把整个工程丢给某个 AI 的程序,才能完成一些特定的任务,这对于追求轻量 IDE 的咱们来讲,还远远不行,因而,我仍是对于这一点抱有很高的期待,这对再次下降前端门槛将是一个很大的奉献。
描绘问题的能力
这尽管不是本文想要提及的主题,大家能够经过比如自己去感受一下。
谢谢你读到了这儿~