为什么要用AI写单测

释放双眼,带上耳机,听听看~!
探讨使用AI写单测的优势和原因,以及对前端开发的影响。

为什么要用AI写单测

这个问题分两点来说,第一是为什么要写单测,第二是为什么要用AI。

先来说为什么写单测,这很简单,我们项目或者说我们前端团队有公共模块,包含有组件类型、工具函数类型、hooks类型等,我们最大也是重点的项目,使用的技术栈是 React,因此这里说的 hooks 是指 react hooks,随着前端队伍壮大,开始考虑用开源的思路来维护这些代码,那么单测就是正规化的其中很重要一环。

至于第二点,主要是考虑提效,所以做一次尝试,项目里有祖传的 Jest 配置,但是具体需要什么依赖,需要根据所写的单测是什么类型,以及当前技术栈是什么版本,这就有一定搭建的学习成本,因此,本次设定为从0到1搭建 Jest 环境到跑通 AI 所写的用例。

使用的IDE

Cursor,版本0.2.5:

为什么要用AI写单测

AI模型:

不是GPT-4

为什么要用AI写单测

想要一直使用中文对话,可以这样配置:

为什么要用AI写单测

点右上角的图标,打开辅助侧栏,点 MORE,然后告诉他,一直使用中文回答,这个配置目前只能有一条。

例子

Github仓库地址:

github.com/bdlite/hook…

用来做例子的分支:

preview/previous

感兴趣的话可以一边 clone 下来,用 Cursor 打开文件夹,然后一边跟着操作。

开始

仓库都有什么

为什么要用AI写单测

  • 有从我们实际项目里剥离出的工程类配置文件,例如 .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 是基于这段代码你可以问些问题,但不在编辑框内生成代码。

为什么要用AI写单测

我这里想让它直接帮我生成注释,便于辅助分析一下这个配置有哪些不妥(懒得看官方文档的这里集合

为什么要用AI写单测
为什么要用AI写单测

生成的是英文,先 Reject,看来辅助侧栏里面配置的在代码编辑框里并不共用,重新调整 Prompt 输入:

为什么要用AI写单测

这一次 Accept:

为什么要用AI写单测

这么读起来,虽然是祖传的配置,似乎看不出什么毛病,当然为了制作例子,其实是有所调整的,至少项目里的路径配的没问题,因此这里的配置也是模拟了一下,路径也没问题,基于此,我们开始让Cursor写用例,然后跑起来看看。

看下源码

为什么要用AI写单测

为了保证环境搭建及后续发布流程比较靠谱,我们先 check 一下哪些是 dependencies,哪些是 devDependencies 和 peerDependencies:

  • ‘react’ 显然不能跟着打包,放 peer
  • ‘query-string’ 这种库还是要严谨点,放 depend

去 package.json 确认一下是否放对了

为什么要用AI写单测

这里有个问题,没有指定 react ,因此我让“助理”帮我加一下:

为什么要用AI写单测
为什么要用AI写单测

accept 之后多了个花括号,手动删吧,谁让它还是个孩子啊。

好戏开场

为什么要用AI写单测

我这是当前打开 package.json 的情况下在侧边栏问的,再试试打开 useSearch.js 的情况下问问:

为什么要用AI写单测

果然当前打开的文件就是提问的上文,可以见到上一个其实并不是我源码实现的内容,我估计是从其他地方找来的答案,果然是一本正经也能胡说八道呀

行,这里的方案给得还是蛮全面的,比方说教你加哪些依赖,手把手教你创建文件,可惜的是,它其实并不能读取整个工程,跨文件去理解上下文,因此它不知道的是,我配了 jest 去读 __tests__ 下的文件

review 下用例

依上文,用例只有三个,只看代码不执行的话,似乎做到了最小的功能检验

再换个思路试试

为什么要用AI写单测

从以上两个提问的答案来看,看懂代码是没问题的,也能指出里面有问题的点,表现不错

为什么要用AI写单测

为什么要用AI写单测

基本上符合源码涉及的几个场景,不过,根据我的判断,似乎还有点问题:

  • 没有开场处的验证 hooks 返回类型的用例

    为什么要用AI写单测

  • 此处的第二个用例:如果 key 不是字符串或者 value 是 null,那么函数不会进行任何操作

    • 看到这个才发现,源码里存在着 bug,为什么在问它有没有 bug 的时候没反应过来,因为当时还没做例子的时候问过,回答是没什么问题,看来这孩子也是变聪明了,也可能是当时的上下文有差异,导致孩子只顾夸,没理性思考,是的,我会去问写得好不好,哈哈
    • bug 就是,其实我们是期望 value 是 null 或者 undefined,那么会清掉 search 中对应的 key

其他问题不大,最多想起来什么场景补充一下就好

run 一下看

按上文提到的,在 __tests__ 目录下创建 useSearch.test.js 文件,然后把刚才的代码复制进去,但是引用 useSearch 函数的路径稍微改一下:

import { useSearch } from 'es/useSearch';

安装 jest 各种依赖

为什么要用AI写单测

根据提示,最省事儿的办法,重新安装,并在命令后加上 –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 命令

该命令的配置同样是祖传的

为什么要用AI写单测

在终端里执行:

npm run test

还得装依赖

为什么要用AI写单测

OK~装它!

为什么要用AI写单测

一步一脚印啊,继续装它!

再执行一次,这次是 Module ts-jest in the transform option was not found.

ts-jest 装完了,然后再 run test

为什么要用AI写单测

做个例子不容易,那就继续装!

但是这里我会都装到 devDependencies,再 run

为什么要用AI写单测

打开推荐的链接

为什么要用AI写单测

OK,试一下 use react-test-renderer

为什么要用AI写单测

装 react,装到 devDependencies,再 run

为什么要用AI写单测

执行成功,祖传的命令写得倒没啥问题,上“链接”:

npm install --save-dev cross-env jest-environment-jsdom ts-jest react-dom react-test-renderer react

分析用例没通过的原因

为什么要用AI写单测

选中这个用例,问下“助理”

为什么要用AI写单测

点 Edit

为什么要用AI写单测

为什么要用AI写单测

好吧,怪我给的自由太过火,重新调整下

为什么要用AI写单测

为什么要用AI写单测

accept 然后跑看看,通过了,不截图了,看下一个

为什么要用AI写单测

这个问题原因一致,但其实,这个不符合我们对这个 hooks 的期待,用错误的源码逻辑来生成错误的用例了属于是,直接改

为什么要用AI写单测

为什么要用AI写单测

为什么要用AI写单测

why?

看下提示中的 Received 就知道了

  • 第三个用例因为源码确实存在这个 bug,这目前来说是按照“预期” failed了
  • 第四个为什么就不对了,第一次能跑出结果的时候不是通过了么,其实跟第二个用例的问题一样,不严谨导致的,这里面每一个用例中的 window 并不处于块级作用域,像第二个一样改过来就好了

让它改第四个

为什么要用AI写单测

为什么要用AI写单测

就剩下第三个用例没跑通了

改源码中的 bug

改源码,选中源码,然后 Edit

为什么要用AI写单测

为什么要用AI写单测

我哭死,感觉它不会写代码,又或者是我的锅?

罢了罢了,先手动改改

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 里改下

为什么要用AI写单测

重新执行

为什么要用AI写单测

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 后报错:

为什么要用AI写单测

用侧边栏的 Chat 求救一下

为什么要用AI写单测

选中用例,Edit

为什么要用AI写单测

为什么要用AI写单测

为什么要用AI写单测

喜提大结局,撒花~

总结

本次实验操作路径

  1. 喂源码
  2. 生成用例
  3. 根据提示搭环境
  4. review 用例和源码
  5. 找出问题并修复
  6. 丰富用例
  7. 遇到报错
  8. 喂错误信息
  9. 根据信息修复
  10. 跑通

如果没有喂给比较合适的上下文,可能会得不到准确的答案。

如果给的描述不够精准,例如我让它修复源码的 bug 就不尽如人意,相信给出足够多,足够精准的信息,应该还是可以的,或许你代码的结构上原本就有点问题,AI 不见得能够懂你希望连结构上的问题一起都能优化的心思,限于本文不是生成代码,而是用例,这一块没有展开来做尝试。

工程领域的期望

这个例子搭建 Jest 的过程还是比较顺利的,我在我们的业务项目里搭建,错误信息很难解,例子中的步骤其实是带有一点上帝视角的,包括里面其实已经自带了配置文件。

目前发现 AI 并不能阅读整个工程的配置、某个指定目录下的文件,据我了解,必须把整个工程丢给某个 AI 的程序,才能实现一些特定的任务,这对于追求轻量 IDE 的我们来讲,还远远不够,因此,我还是对于这一点抱有很高的期待,这对再次降低前端门槛将是一个很大的贡献。

描述问题的能力

这虽然不是本文想要提及的主题,大家可以通过例子自己去感受一下。

谢谢你读到了这里~

本网站的内容主要来自互联网上的各种资源,仅供参考和信息分享之用,不代表本网站拥有相关版权或知识产权。如您认为内容侵犯您的权益,请联系我们,我们将尽快采取行动,包括删除或更正。
AI教程

阿里达摩院发布mPLUG-Owl:多模态大模型展示出优异能力

2023-12-15 18:10:14

AI教程

使用PPO算法训练强化学习模型actor-critic

2023-12-15 18:21:14

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索