利用ChatGPT协助编写单元测试

ChatGPT自从2022年推出以来受到很多人的喜欢,此篇博客重点介绍如何修改Prompt来自动生成较理想的单元测试。如下图所示的一段代码,该class中有一个public方法toLocale(),其余都是private方法,toLocale()方法会调用private的方法。(备注:下面的方法特地写了比较多的分支逻辑,来验证chatGPT编写的单元测试的覆盖率情况)

package com.github.secondCourse;
import java.util.Locale;
public class LocaleUtils {private static final String EMPTY = "";public Locale toLocale(final String str) {if (str == null) {return null;}if (str.isEmpty()) { // LANG-941 - JDK 8 introduced an empty locale where all fields are blankreturn new Locale(EMPTY, EMPTY);}if (str.contains("#")) { // LANG-879 - Cannot handle Java 7 script & extensionsthrow new IllegalArgumentException("Invalid locale format: " + str);}final int len = str.length();if (len < 2) {throw new IllegalArgumentException("Invalid locale format: " + str);}final char ch0 = str.charAt(0);if (ch0 == '_') {if (len < 3) {throw new IllegalArgumentException("Invalid locale format: " + str);}final char ch1 = str.charAt(1);final char ch2 = str.charAt(2);if (!Character.isUpperCase(ch1) || !Character.isUpperCase(ch2)) {throw new IllegalArgumentException("Invalid locale format: " + str);}if (len == 3) {return new Locale(EMPTY, str.substring(1, 3));}if (len < 5) {throw new IllegalArgumentException("Invalid locale format: " + str);}if (str.charAt(3) != '_') {throw new IllegalArgumentException("Invalid locale format: " + str);}return new Locale(EMPTY, str.substring(1, 3), str.substring(4));}return parseLocale(str);}private Locale parseLocale(final String str) {if (isISO639LanguageCode(str)) {return new Locale(str);}final String[] segments = str.split("_", -1);final String language = segments[0];if (segments.length == 2) {final String country = segments[1];if (isISO639LanguageCode(language) && isISO3166CountryCode(country) ||isNumericAreaCode(country)) {return new Locale(language, country);}} else if (segments.length == 3) {final String country = segments[1];final String variant = segments[2];if (isISO639LanguageCode(language) &&(country.length() == 0 || isISO3166CountryCode(country) || isNumericAreaCode(country)) &&variant.length() > 0) {return new Locale(language, country, variant);}}throw new IllegalArgumentException("Invalid locale format: " + str);}private boolean isISO639LanguageCode(final String str) {return isAllLowerCase(str) && (str.length() == 2 || str.length() == 3);}private boolean isISO3166CountryCode(final String str) {return isAllUpperCase(str) && str.length() == 2;}private boolean isNumericAreaCode(final String str) {return isNumeric(str) && str.length() == 3;}private boolean isAllLowerCase(final CharSequence cs) {if (cs == null || isEmpty(cs)) {return false;}final int sz = cs.length();for (int i = 0; i < sz; i++) {if (!Character.isLowerCase(cs.charAt(i))) {return false;}}return true;}private boolean isAllUpperCase(final CharSequence cs) {if (cs == null || isEmpty(cs)) {return false;}final int sz = cs.length();for (int i = 0; i < sz; i++) {if (!Character.isUpperCase(cs.charAt(i))) {return false;}}return true;}private boolean isEmpty(final CharSequence cs) {return cs == null || cs.length() == 0;}private boolean isNumeric(final CharSequence cs) {if (isEmpty(cs)) {return false;}final int sz = cs.length();for (int i = 0; i < sz; i++) {if (!Character.isDigit(cs.charAt(i))) {return false;}}return true;}
}

下面是原来为这个class编写的单元测试,运行测试,覆盖率在80%左右。

public class LocalUtilsTest {private LocaleUtils localeUtils;@Rulepublic ExpectedException exception = ExpectedException.none();@Beforepublic void setUp() {localeUtils= new LocaleUtils();}@Test()public void should_return_null_when_str_is_null() {assertThat(localeUtils.toLocale(null)).isEqualTo(null);}@Test()public void should_call_isEmpty_when_str_is_empty() {assertThat(localeUtils.toLocale("").getLanguage().isEmpty());assertThat(localeUtils.toLocale("").getCountry().isEmpty());}@Testpublic void should_throw_exception_when_str_is_not_valid() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: #");localeUtils.toLocale("#");}@Testpublic void should_throw_exception_when_strLength_is_less_2(){exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: a");localeUtils.toLocale("a");}@Testpublic void should_throw_exception_when_strLength_is_less_3() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: _a");localeUtils.toLocale("_a");}@Testpublic void should_throw_exception_when_strLength_is_3_and_is_lowercase() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: _Aa");localeUtils.toLocale("_Aa");}@Testpublic void should_return_locale_when_strLength_is_3() {assertThat(localeUtils.toLocale("_AB").getCountry()).isEqualTo("AB");}@Testpublic void should_throw_exception_when_strLength_is_4() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: _ABC");localeUtils.toLocale("_ABC");}@Testpublic void should_throw_exception_when_str_3_is_not_valid(){exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: _ABC_");localeUtils.toLocale("_ABC_");}@Testpublic void should_return_locale_when_strLength_is_5() {assertThat(localeUtils.toLocale("_AB_DE").getCountry()).isEqualTo("AB");}@Testpublic void should_return_locale_when_str_is_ISO639LanguageCode_and_length_is_2() {assertThat(localeUtils.toLocale("ab").getLanguage()).isEqualTo("ab");}@Testpublic void should_return_locale_when_str_is_ISO639LanguageCode_and_length_is_3() {assertThat(localeUtils.toLocale("abc").getLanguage()).isEqualTo("abc");}@Testpublic void should_return_locale_include_language_country_when_str_is_abc_AB() {assertThat(localeUtils.toLocale("abc_AB").getLanguage()).isEqualTo("abc");assertThat(localeUtils.toLocale("abc_AB").getCountry()).isEqualTo("AB");}@Testpublic void should_return_locale_include_language_country_when_str_is_abc_123() {assertThat(localeUtils.toLocale("abc_123").getLanguage()).isEqualTo("abc");assertThat(localeUtils.toLocale("abc_123").getCountry()).isEqualTo("123");}@Testpublic void should_return_locale_include_language_country_variant_when_str_is_abc_123_ef() {assertThat(localeUtils.toLocale("abc_123_ab").getLanguage()).isEqualTo("abc");assertThat(localeUtils.toLocale("abc_123_ab").getCountry()).isEqualTo("123");assertThat(localeUtils.toLocale("abc_123_ef").getVariant()).isEqualTo("ef");}@Testpublic void should_throw_exception_when_str_is_abc_123_ef_d() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: abc_123_ef_d");localeUtils.toLocale("abc_123_ef_d");}@Testpublic void should_throw_exception_when_str_substring_is_not_ISO3166CountryCode() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: abc_aB");localeUtils.toLocale("abc_aB");}@Testpublic void should_throw_exception_when_str_is_not_ISO639LanguageCode() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: abC");localeUtils.toLocale("abC");}@Testpublic void should_throw_exception_when_str_substring_is_not_NumericAreaCode() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: abc_");localeUtils.toLocale("abc_");}@Testpublic void should_throw_exception_when_parsed_variant_length_is_0() {exception.expect(IllegalArgumentException.class);exception.expectMessage("Invalid locale format: abc_AB_");localeUtils.toLocale("abc_AB_");}
}

删除上面的单元测试,尝试用ChatGPT来自动化为上面的class编写单元测试,如下图所示:左边是输入的prompt,右边是ChatGPT生成的代码。

生成的单元测试的名称不是用下滑线分割,但是我更喜欢用下滑线来分割单元测试名称,另外,默认是用Assert来进行断言,我更希望用AssertJ来作为断言库,那么可以在上面的promp的基础上进行修改,结果如下所示:除了修改单元测试名称和断言库外,上一版本生成的单元测试中对于异常的验证使用了assertThrows方法,实际该方法不存在,所以再次修改promp,让chatGPT用ExpectedException来编写异常情况的case。

经过上面的修改后,编写全新的prompt,让chatGPT再次生成新的单元测试,修改后的Prompt如下所示:,copy单元测试到IDE工具上,虽然得到的覆盖率有点低(如下所示),但可直接运行,无任何报错:

此时,再修改prompt添加了覆盖率的要求,此时,chatGPT对私有方法编写了单元测试,但同时也给出了提示信息“不建议对私有方法编写单元测试,应该直接调用公有方法进行覆盖”,具体如下所示:

另外,因为ChatGPT默认返回的tokens数量是4096,这包括输入的prompt的tokens个数和返回的response的tokens个数,所以,对于很长的代码,一次性生成完整的单元测试有难度,针对这种情况,建议在生成的基础版本上有针对的添加剩余的单元测试,即给ChatGPT更多的上下文信息来驱动生成单元测试。以下图为例,查看未覆盖的代码,针对性的给出prompt,让单元测试进一步完善。

修改Prompt,针对性的补充未覆盖的单元测试,修改后的prompt和自动生产的单元测试结果如下所示:可以看到单元测试中生成了len==3的case,另外还生成了len大于4的case,而对于边界值校验来说,真正需要的len是等于5和小于5且不等于3的情况,例如len==4的case,所以,在自动生成的基础上稍微修改下input就可以达到这个效果。

总结而言,在prompt中基础的输入信息是"用junit,assertjs编写单元测试,且单元测试方法名称用下划线分割,方法名称以should开头,异常验证部分使用Junit中的ExpectedException",在基础prompt上,再结合实际情况输入针对性信息,即可借助chatGPT编写单元测试。

另外,需要注意一点:chatGPT有tokens的限制,所以,对于比较大的class,需要分段输入给chatGPT,否则返回的response结果有限。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21689.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

32岁医生放弃医院编制,转行去做程序员!

这年头大环境不好&#xff0c;程序员都想方设法往体制内跑&#xff0c;希望能端起稳定的铁饭碗。但也有人是逆行者&#xff0c;明明在体制内&#xff0c;却非要跳出去当程序员。 一个网友发帖说自己今年32岁&#xff0c;放弃了月薪7500元的二甲医院编制&#xff0c;转行去做ja…

文心一言发布我怎么看?

文心一言发布我怎么看? 文心一言发布会我只简短的回答两个问题:补充&#xff1a; 文心一言发布会 有想看发布会视频的朋友,关注爱书不爱输的程序猿,私信找我拿 我只简短的回答两个问题: 1.文心一言能否为百度止颓&#xff1f; 首先,百度的颓势是由于多种因素导致的&#xff0c…

ChatGPT - 生成新的想法并克服写作的障碍

文章目录 Prompt Prompt “我正在撰写有关[主题]的博客文章。为此博客文章提供一个包含10个要点的大纲。还给我5个引人注目的标题选项。”大纲&#xff1a;I. 介绍Flink - Flink是什么&#xff1f; - Flink的特点 - Flink的应用场景II. Flink的核心概念 - 流处理 vs 批处理 - …

革新写作方式:ChatGPT最新版带来高质量聚合文章的批量生成

随着人工智能技术的不断发展&#xff0c;自然语言处理模型也在不断进步。ChatGPT最新版作为一种强大的语言模型&#xff0c;可以生成高质量的聚合文章&#xff0c;为写作方式带来了革新。本文将详细阐述ChatGPT最新版带来的革新之处&#xff0c;包括其应用领域、生成文章的流程…

自动插入匹配与标题相关的百度图片或者搜狗图片软件-批量插入txt文档-Chatgpt批量写文章配图神器

1、我们用《Chatgpt 3.5-turbo软件》批量生成txt文档&#xff0c;但是这样txt文档里不带图片&#xff0c;直接发布到网站上&#xff0c;光有文字没有图片&#xff0c;效果也不是很理想&#xff0c;就需要一款配图软件。 2、该软件根据txt标题自动匹配百度图片或者搜狗图片里的…

ChatGPT最新版实现多样化聚合文章的批量生成文章

随着人工智能技术的不断发展&#xff0c;ChatGPT最新版在多样化聚合文章的批量生成方面取得了重要突破。本文将从随机选取的8个方面&#xff0c;对ChatGPT最新版的构建思想进行详细阐述。这些方面包括&#xff1a;自然语言处理、大规模数据集、迁移学习、多模态输入、生成模型优…

Python小案例:回合制奥特曼打怪兽游戏

from abc import ABCMeta, abstractmethod from random import randint, randrange import timeclass Fighter(object, metaclassABCMeta):"""战斗者"""# 通过__slots__魔法限定对象可以绑定的成员变量__slots__ (_name, _hp)def __init__(self…

奥特曼系列赛文飞踢是哪个服务器,昭和系6大奥特曼的“奥特飞踢”,泰罗的很敏捷,雷欧伤害最高!...

说起“奥特飞踢”那可是奥特曼格斗技能中非常炫酷的招式了&#xff0c;而且还能给怪兽造成不俗的伤害。记得小时候的小编在看奥特曼使用“奥特飞踢”打击怪兽时可是非常激动的&#xff0c;有时候甚至还幻想过自己也能使用这一招。毕竟小编不是练武术的&#xff0c;所以与这一招…

奥特曼系列ol光元在哪个服务器,奥特曼系列ol如何快速获得光元 奥特曼系列ol怎样快速获得光元...

奥特曼系列OL怎么刷光元&#xff1f;奥特曼系列ol刷光元bug有吗&#xff1f;奥特曼系列ol刷光元软件是真是假&#xff1f;奥特曼系列ol常规刷光元的方法是可以通过完成每日任务和成就任务来积累&#xff0c;但是这个过程比较长&#xff0c;需要长时间才能积累大量的光元。那么还…

7月6号奥特曼服务器维护中,泰迦奥特曼:7月6号开播,泰迦是泰罗儿子,优幸可变为三个奥特曼...

原标题&#xff1a;泰迦奥特曼&#xff1a;7月6号开播&#xff0c;泰迦是泰罗儿子&#xff0c;优幸可变为三个奥特曼 令和时代到来&#xff0c;奥特曼系列也将迎来全新的篇章&#xff0c;作为令和第一位奥特曼&#xff0c;不出预料的就是泰罗的儿子泰迦奥特曼。这一次官方总算实…

奥特曼系列ol如何进老服务器,《奥特曼系列OL》新手攻略

第一步就是最快速度进驻服务器&#xff0c;一般早上10点开服&#xff0c;游戏都这样&#xff0c;早点冲进去??这点很重要&#xff01;理由在后面说 引导中的第一次抽卡 目前已知的第一抽可能有的角色是赛罗、阿古茹、阿斯特拉、希卡利。 从实战角度考虑&#xff0c;最有用的应…

奥特曼系列ol光元在哪个服务器,奥特曼系列ol光元怎么合理使用

奥特曼系列ol光元怎么合理使用 2016-02-21 作者&#xff1a;说玩小编 来源&#xff1a;说玩网 评论(9条) 我要评论 奥特曼系列ol光元怎么合理使用?在游戏中&#xff0c;光元是很珍贵且数量稀少的&#xff0c;我们平时在使用光元的时候是需要合理利用的&#xff0c;那么奥特曼系…

奥特曼系列服务器,奥特曼系列ol无限光元

奥特曼系列ol无限光元这款游戏的奥特曼非常的多&#xff0c;操作比较的不错&#xff0c;玩起来非常的给力带劲儿哟&#xff0c;剧情也是比较的丰富的&#xff0c;玩起来很有代入感哟&#xff0c;各种酷炫的动作非常的炫目的哟&#xff01; 奥特曼系列ol无限光元玩家评论&#x…

Sam Altman 山姆奥特曼:如何成功 ?How To Be Successful

Sam Altman 山姆奥特曼:如何成功 ?How To Be Successful 目录 Sam Altman 山姆奥特曼:如何成功 ?How To Be Successful How To Be Successful如何成功

绘制一只奥特曼DIY

原文链接&#xff1a;https://codebus.cn/luoyh/ultraman 奥特曼的组成 奥特曼是由斜的椭圆&#xff0c;圆角矩形&#xff0c;圆形&#xff0c;以及曲线的组成的。此处绘制中&#xff0c;主要应用了曲线的的绘制&#xff0c;将奥特曼画的比较饱满。 值得学习的地方 本次绘制…

本期推送应该是全网最全的奥特曼表情包合集

奥特曼00298-戳死水B楼主.jpg 奥特曼00297-青峰在手谁能一剑屠龙.jpg 奥特曼00001-安排.jpg 奥特曼00002-咕叽咕叽啪啦啪啦.gif 奥特曼00003-校服校霸.jpg 奥特曼00004-摇滚奥特曼.gif 奥特曼00005-诸葛亮变色赛文.gif 奥特曼00006-奥特曼打工.gif 奥特曼00007-让老子看看你是什…

卖奥特曼卡片年入十亿:赚钱这事,你还得相信光的力量

我读小学的侄子告诉我&#xff0c;现在就连小学生的爱情都这么物质了。和他们班班花约会&#xff0c;明码标价&#xff1a;约会一次给她一张她没有的HR卡。如果有一张LGR卡&#xff0c;就可以直接奔现。 “没有黑金卡的爱情就像是一盘散沙&#xff0c;都不用风吹&#xff0c;打…

埃隆 · 马斯克、山姆 · 奥特曼和 OpenAI 的秘史

三年后&#xff0c;埃隆马斯克准备放弃他帮助创立的人工智能研究公司 OpenAI。 OpenAI 这家非营利组织于 2015 年推出&#xff0c;得到了马斯克和里德霍夫曼等亿万富翁科技名人的支持&#xff0c;他们曾作为一个团体认捐 10 亿美元。它吸引了该领域的一些顶尖人才离开大型科技公…

奥特曼与钢铁侠【InsCode Stable Diffusion美图活动一期】

文章目录 简介图片生成步骤更多体验方式 简介 InsCode 是一个一站式的软件开发服务平台&#xff0c;从开发-部署-运维-运营&#xff0c;都可以在 InsCode 轻松完成。 InsCode 的 Ins 是 Inspiration&#xff0c;意思是创作、寻找有灵感的代码。 Stable Diffusion是文图生成模型…

速卖通、阿里国际、shopee618盛典!提升订单销量的秘密武器—测评补单技术!

随着电子商务的迅速发展&#xff0c;网络购物已成为现代人生活中不可或缺的一部分。而在众多购物平台中&#xff0c;速卖通凭借其丰富多样的商品选择和优惠的价格政策&#xff0c;成为了全球消费者的首选之一。尤其是每年的618盛典&#xff0c;更是吸引了大量消费者的目光。然而…