实战案例|利用 MarsCode 内置的 DeepSeek 服务,单元测试耗时缩短70%!


资料来源:火山引擎-开发者社区

单元测试总在奇怪的地方卡 bug?Mock 配置像解谜游戏、边界条件比数学题还烧脑?

没关系!

MarsCode 编程助手 X 三款大模型(DeepSeek V3、DeepSeek R1、豆包大模型1.5 )帮你解决所有问题

无需配置,性能Top,代码准确率嗖嗖🚀

用过的朋友都说:  “以前写测试像开手动挡,现在像开了自动巡航” ,速看~👇👇👇

准备工作

在正式开始单元测试之前,我们先做好相关准备👇

  1.                下载/更新MarsCode 编程助手

1️⃣如果你是新用户,以Visual Studio Code中为例,打开VSCode 扩展窗口,在搜索窗口搜索MarsCode,找到MarsCode 插件单击「install」,完成安装,登录即可使用MarsCode 编程助手。

2️⃣ 如果你是老用户,请更新MarsCode 编程助手到最新版本(若开启了自动更新,则将会自动更新),更新后重启IDE即可

*VSCode:1.1.62

*JetBrains:1.2.1.15

  1.                克隆案例项目

本次案例使用的是AI生成的一个最基础的React项目,目的是模拟学习工作中最真实的场景,方便大家迅速掌握快速搭建单元测试环境以及生成单元测试用例的技巧。

Bash
         
             
           git clone https://github.com/ylx911229/unit-test\_back.git
         
       

  1.                单元测试基础

*因为后续案例选用的是Jest作为单元测试框架,所以介绍的基础内容主要以Jest框架为标准

•                     概念介绍

1️⃣  断言(Assertion) :用于验证测试结果是否符合预期的语句,如  Expect

2️⃣  测试替身(Test Double) :用于替代真实依赖的模拟对象,确保测试的隔离性,如 Mock、Jest.fn

3️⃣  测试覆盖率(Test Coverage) :用于衡量测试用例覆盖代码的比例,如  行覆盖率、分支覆盖率

•                     单元测试文件命名规范

生成的单元测试文件名必须以  .test.ts/.test.js 作为结尾,否则单元测试框架无法读取并执行单元测试用例

•                     运行单元测试用例

Markdown
         
             
           npx jest --coverage
         
       

实战跟练

STEP1:搭建测试环境

首先来搭建一下单元测试的环境,向MarsCode输入以下提示词:

Markdown
         
             
           Workspace 帮我为整个项目搭建一下单元测试的环境
         
       

可以看到MarsCode给我们推荐的单元测试框架是Jest,这是一个流行的JavaScript测试框架,特别适合用于单元测试。

另外,React组件的单元测试,依赖 React Testing Library ,RTL是当前 React 生态中最流行的组件测试解决方案,它提供了一套更贴近真实用户行为的测试工具链。

STEP2:单元测试用例编写

关于单元测试用例,将从函数类和UI类等不同的方式类型来举例实现

•                     函数类

1️⃣ 纯函数 & 工具类 对于纯函数的工具类单元测试,特点是输入输出明确,无副作用,整体测试重点是 输出格式验证和唯一性检查,接下来以  生成唯一 ID 为例:

JavaScript
// 生成唯一 IDfunction generateId(prefix) {
           return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;
           
}
       

我们可以打开src\utils\tool-utils.js,选中代码,在对话框直接选择/test功能形成单元测试:

将生成的单测代码另存为tool-utils.test.js,保存后执行得到如下效果:

结果显示覆盖率100%,但是有一个用例并未通过,显示特殊字符作为前缀输出的结果未匹配正则。

我们可以切换到DeepSeek R1模型并选中文件,将出现的问题告诉MarsCode后将生成的代码替换进原来的tool-utils.test.js,再次运行 npx jest --coverage 可以发现问题已解决~

如果test代码未运行成功出现报错,可以将报错内容复制给MarsCode,利用AI问答继续解决问题。

2️⃣ 数据转换 & 验证

接下来以用户资料表单处理器为例,处理结构化数据或验证规则,这则测试案例重点在于正常数据清洗(trim、类型转换)、异常输入(空值、非法邮箱、年龄不足)、 及错误消息准确性,打开validate-utils.js,选择生成单测:

JavaScript
// 转换并验证用户输入
export const processUserInput = (formData) => {
 const result = {
           name: formData.name.trim(),
           age: parseInt(formData.age, 10),
           email: formData.email.toLowerCase()
 };
           
           if (isNaN(result.age)) {
           throw new Error('Invalid age: must be a number');
 }
           
           if (!/^[\w.+]+@\w+\.\w+$/.test(result.email)) throw new Error('Invalid email');
           if (result.age < 18) throw new Error('Underage');
           
 
           return resu<
           
}
       

同样将MarsCode生成的单测代码保存为validate-utils.test.js后运行,效果如下:

3️⃣ 状态管理 & 业务逻辑 现在我们来探讨更复杂业务逻辑下的单测,以购物车 Redux reducer为例,涉及核心业务规则或全局状态变更,这个案例中我们的测试重点在

•                     商品添加逻辑(新增 vs 增量)

•                     促销码有效性验证

•                     不可变数据检查

JavaScript
// cartReducer 函数
export const cartReducer = (state = { items: [] }, action) => {
           switch (action.type) {
           case 'ADD_ITEM':
           const existing = state.items.find(item => item.id === action.payload.id);
           if (existing) {
           return {
         ...state,
           items: state.items.map(item =>
           item.id === action.payload.id
             ? { ...item, qty: item.qty + 1 }
             : item
         )
       };
     }
           return { ...state, items: [...state.items, action.payload] };
           
     
           case 'APPLY_PROMO':
           if (!action.payload.isValid) return state;
           return { ...state, promoCode: action.payload.code };
           
     
           default:
           return state;
 }
           
}
       

现在打开businuss-utils.js,同样选中/test 生成单测:

将MarsCode 生成的新文件保存为businuss-utils.test.js,运行单测命令,得到如下效果:

•                     UI类

我们以用户输入花费金额的REACT组件为例,我们单测的重点在于事件是否能正确触发以及UI是否能正常显示,打开react-test.jsx文件:

JavaScript
import React from 'react';
           
import { render, fireEvent } from '@testing-library/react';
           
import { CostInput } from './react-test';
           
           
describe('CostInput Component', () => {
           beforeEach(() => {
   jest.clearAllMocks();
           
           // 设置全局变量
           global.navigator = {
           // 传入navigator的值
   };
           
           global.document = {
           // 传入document的值
   };
           
           global.window = {
           // 传入window的值
   };
           
           global.otherVariables = {
           // 传入otherVariables的值
   };
 });
           
           test('renders without crashing', () => {
           render(<CostInput />);
 });
           
           test('calls handleChange when the input changes with valid number', () => {
           const handleChange = jest.fn();
           const { getByLabelText } = render(<CostInput handleChange={handleChange} />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: '123' } });
           expect(handleChange).toHaveBeenCalled();
 });
           
           test('does not call handleChange when the input is invalid', () => {
           const handleChange = jest.fn();
           const { getByLabelText } = render(<CostInput handleChange={handleChange} />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: 'abc' } });
           expect(handleChange).toHaveBeenCalled();
 });
           
           test('displays the correct value with dollar sign', () => {
           const { getByLabelText } = render(<CostInput />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: '123' } });
           expect(getByLabelText('cost-input')).toHaveValue('$123');
 });
           
           test('displays empty value when input is invalid', () => {
           const { getByLabelText } = render(<CostInput />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: 'abc' } });
           expect(getByLabelText('cost-input')).toHaveValue('');
 });
           
           test('handles initial dollar sign correctly', () => {
           const { getByLabelText } = render(<CostInput />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: '$123' } });
           expect(getByLabelText('cost-input')).toHaveValue('$123');
 });
           
           test('handles empty input correctly', () => {
           const { getByLabelText } = render(<CostInput />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: '' } });
           expect(getByLabelText('cost-input')).toHaveValue('');
 });
           
           test('handles input with leading zeros correctly', () => {
           const { getByLabelText } = render(<CostInput />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: '00123' } });
           expect(getByLabelText('cost-input')).toHaveValue('$123');
 });
           
           test('handles input with multiple dollar signs correctly', () => {
           const { getByLabelText } = render(<CostInput />);
   fireEvent.change(getByLabelText('cost-input'), { target: { value: '$$123' } });
           expect(getByLabelText('cost-input')).toHaveValue('$123');
 });
           
});
       

向MarsCode 输入单测/test,同样将生成的代码另存为react_tes t.test.js进行运行,运行之后发现单测覆盖率只有62.5%,不太理想。

我们可以继续让MarsCode 生成单测补充用例,提高覆盖率

应 用代码后,可以看到单测覆盖率 提升到83.33%,同时帮我们优化了部分代码,甚至对原来的handleChange函数进行了优化,提升了代码质量。

通过本次实践,我们不仅掌握了单元测试的核心价值与实施方法,更验证了 MarsCode 在提升代码质量方面的工程价值。 相信在更复杂的业务场景下,优秀的工具能帮助开发者释放更多生产力。


相關推薦

2024-08-10

满足不同行业不同场景的数据分析需求,具备丰富的落地实战经验。未来,飞轮科技将继续深化功能创新优化与行业应用实践,为全球用户带来更加实时、统一、弹性、开放的数据分析体验。 飞轮科技加入数据库应用创新实验

2021-11-22

背景 在日常工作中,我们通常需要存储一些日志,譬如用户请求的出入参、系统运行时打印的一些info、error之类的日志,从而对系统在运行时出现的问题有排查的依据。 日志存储和检索是个很常见且简单的工作,市面也有

2022-11-02

能更智能地进行搜索,更快地诊断日志速率峰值,并分配案例以便于协作。Elastic Cloud 8.5 版还提供了一个新的运行状况页面,可以轻松识别和解决集群性能问题。 更多详情可查看:https://www.elastic.co/blog/whats-new-elastic-8-5-0

2023-03-21

软成为全球第一。 在基础软件方面,腾讯目前已具备服务器操作系统的全链路自研能力,发起并深度参与了 OpenCloudOS 操作系统开源社区;以及连续第六年入围全球企业KVM开源贡献榜,KVM 是 Linux 内核的核心模块之

2025-03-20

全国大学生同上一堂人工智能大课”主讲专家。 著有《DeepSeek全攻略》、《走进具身智能》等广受欢迎的科普书。 OSCHINA 有幸邀请到了陈光教授(@爱可可-爱生活)做客「高手问答」栏目,和大家一起聊聊 AI。 本月初,陈光

2025-03-25

、can、i2c、spi、pin、dac、rtc、adc 驱动示例。 嵌入式开发实战指南 a. 更新 STM32 BSP 制作教程。 b. 图解 SLAB 与 MEMPOOL 差异,新增碎片化治理实战案例。 8 单元测试 测试覆盖率飞跃 a. 新增 rt_memcpy、rt_memset、rt_memcmp 边界测试用

2025-04-03

队一直在等待国内有能力支持 AutoDev 的国产模型,直到 DeepSeek V3-0324出现。 AutoDev 开源已有两年时间,如今已经进化成集成度最好的 JetBrains IDE 上的第二代 AI 编程工具,支持主流的 Intellij IDEA、WebStrom、Clion 等 IDE,还有基于 Intel

2025-03-26

上新!DeepSeek-V3重磅升级 昨夜,DeepSeek-V3迎来一波更新,升级至「DeepSeek-V3-0324」版本。 不仅将模型参数量由原版的671B提升至685B,编程、数学等推理思考能力大幅提升,性能表现可以与Claude 3.5/3.7 Sonnet相媲美。同时,模型的开

2024-10-22

3 [feat]需要定义数据同步可自定义表列映射#225 经典案例 多源同步Doris Installation TIS Package 安装说明 (https://tis.pub/docs/install/tis/uber)  TIS Flink Standalone Package 安装说明 (https://tis.pub/docs/install/flink-cluster

2024-07-24

ism 收入官方 PDK 库,实现了海外社区支持下的第一个实用案例。 在教育领域,我们致力于培养编程语言这一基础软件领域的后备人才。MoonBit 创始人张宏波在清华大学等国内多所知名高校和 APIO 2024(亚洲与太平洋地区信息

2022-12-26

需要坐着等待他们的机器关闭。它还将鼓励用户正确使用内置的关机 API。 更多内容查看:https://fedoraproject.org/wiki/Changes/Shorter_Shutdown_Timer

2023-07-15

: 使MetaGPT能够自我演化,实现自我训练、微调、优化、利用和更新 短期目标: 成为ROI最高的多代理框架。 支持中等规模项目(约2000行代码)的全自动实施。 实施大多数已识别的任务,达到0.5版本。 任务 要达到v0.5

2024-08-29

兼容java8和java17,理论11也可以 官方提供基于ruoyi-vue封装实战项目,很实用 演示地址 admin/admin123 演示地址:http://www.hhzai.top 官网 http://warm-flow.cn

2025-03-25

Xinference v1.4.0 发布 🚀! ✨ Gemma-3 模型重磅来袭,DeepSeek-v3 现已支持 Function Calling! 🎉 社区贡献者突破 100+!感谢大家的支持,期待更多伙伴加入贡献代码 💪💖。 🌍 社区版 📌 更新指南 * Pip:pip install 'xinference==1.4.0