【ChatGPT-应用篇】基于chatGPT覆盖测试过程的初步探索

chatgpt,应用,基于,覆盖,测试,过程,初步,探索 · 浏览次数 : 116

小编点评

**代码简介:** 该代码展示了如何使用 po模式、并发等高级用法来实现 ChatGPT 的功能。 **主要功能:** * **关键字驱动:**通过测试代码,发现 ChatGPT 的核心功能是通过多个关键字驱动来实现的。 * **并发:**使用多个线程来实现 ChatGPT 的并发执行。 * **数据驱动:**通过测试代码,发现 ChatGPT 使用数据驱动来实现其功能。 **主要问题:** * **代码复杂性:**代码使用多个 po模式、并发等高级用法,导致代码复杂性。 * **测试难度:**测试代码需要通过多个测试用例来验证 ChatGPT 的功能。 * **性能优化:**代码需要进行性能优化,以提高 ChatGPT 的效率。 **建议:** * **优化代码复杂性:**尝试通过代码优化来减少代码复杂性。 * **提高测试效率:**通过测试效率来提高测试代码的测试效率。 * **进行性能优化:**通过性能优化来提高 ChatGPT 的效率。

正文

1、前言

22年底ChatGPT就已风靡行业内外,简单来说,它是基于自然语言生成式 AI 模型,打造的一款聊天机器人。是 OpenAI 于 11 月 30 日推出的最新作品,供公众免费测试。他可以根据用户的提示,模仿类似人类的对话,和普通的智能机器人有天地之别,非常真实。我们跟他说各种内容,比如写代码、汇总周报、写邮件、写诗句、查百科什么的,ChatGPT 都对答如流,根本不在话下。

圈内开始尝试利用chatGPT提升工作效率,比如VSCode,IDE 插件市场迅速上线 ChatGPT,诸多大神也纷纷基于chatGPT搭建微信、浏览器插件、客户端等。

如此火爆之势,作为测试人员对此也颇为好奇,简单的人机对话有哪些可以帮助我们测试工作呢?本文主要谈从测试视角,结合测试流程来看chatGPT的应用。

2、测试流程介绍

结合团队现有测试流程如下:

我们按照测试流程,拆解具体任务,测试人员在每个环节需要输出什么内容呢?

  • 分析需求,编写测试计划,明确测试策略,包含安全、性能等,输出测试排期;
  • 提炼出测试点,以功能点具体拆分测试用例,包含冒烟用例、流程用例、异常用例、联调用例等;
  • 根据接口定义,提前准备自动化脚本,测试阶段按照业务流程增加断言及脚本调优;

再来细化,测试计划,提炼功能,这些必然需要测试人员通过自己对PRD的分析,对业务的熟悉后逐一定制,那GPT既然是人工智能对话,那我将总结出的“固定需求”对他进行发问,看看他的产出。

3、GPT答案评估

编写测试用例

按照提炼出的测试点,以简明扼要的语言与他沟通一轮,

接着,由于 ChatGPT 有记忆功能,它能知道刚才我们让它干了什么,

再给他些引导,让他继续

换一个GPT客户端再试一轮呢

上图所示,他的回答基本属于测试基础常识,距离真正的工作中的用例要求还是相差很多,甚至有些答非所问。我问的边界值,等价类,判定表等都没有回答到位,仿佛依然从他所学所会的库里翻找,在拍脑袋随机写用例,而且和最开始问的自营车新增接口仿佛没有特定关联。但用来作为补充和借鉴是非常好的。把他当做搜索引擎来用,结果聚合度高,不用搜索多个页面,自己汇总模板答案。

编写自动化脚本

到了第二步骤,随着测试前置不断推进,我们期望自动化占比冒烟用例的比例逐步提升,那如何能够提升自动化脚本的编写速度,我们来看看GPT能不能助我们一臂之力呢?

先来接口自动化的试试

然后同样的场景问问UI的呢

如上,他回答问题时会出现偶尔中断情况,需要我们再耐心一点继续发问

如上GPT给出了一个简单的线性脚本。他的答案不能直接copy,可能他的知识库没有覆盖足够的业务场景?

所以干脆我们直接跳过业务,问一个基础登录的示例,看看我们能用到哪些呢?

长截图不方便那我直接copy出来代码:

from seLenium import webdriver
import time
#设置测览器塑动路径
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')

# 打开网址
driver.get('http:/example/")

# 验证用户名和密码输入框是否存在
assert driver.find_element_by_name('username')
assert driver.find_element_by_name('password')

# 测试无效用户名和密码
invalid_username ='fakeuser'
invalid_password ='fakepass'
driver.find_element_by_name('username').send_keys(invalid_username)
driver.find_element_by_name('password').send_keys(invalid_password)
driver.find_element_by_css_selector('button[type="submit"]').click()

# 检查错误消息是香正碑量示
error_msg= driver.find_element_by_css_selector(',alert-danger').text
assert "用户名或密码不正确" in error_msg

# 测试正确凭证
valid_username = 'testuser'
valid_password = 'testpass'

driver.find_element_by_name('username').clear()
driver.find_element_by_name('username').send_keys(vaLid_username)
driver.find_element_by_name('password').clear()
driver.find_element_by_name('password').send_keys(valid_password)
driver.find_element_by_name("button[type="submit"]') .click()

# 验证是否成功跳转到主页
time.sleep(1) #等待页面刷新
assert driver.current_url == 'http://example.cn/home/'

# 验证是显示用户信息
user_info = driver.find_element_by_css_selector('userinfo').text
assert valid_username in user_info

# 退出登录
driver.find_element_by_link_text("退出"),click()

# 关闭浏览器
driver.quit()


selenium自动化脚本的启动和收尾没太大问题;然后验证用户名密码输入框是否存在,如果不存在就报错了;然后用一个错误的用户名密码 登录了一次,验证提示语是否正确;然后又登录了一次正确的用户名密码,验证是否可以跳转到主页;然后又验证了一下主页的用户名显示元素是否包含用户名;最后点击退出按钮,然后关闭浏览器。

分析以上脚本:

优点:GPT写的代码基本没有语法问题,支持扫描被测试页面中的几个关键元素的定位;代码注释这点我觉得特别不错,是一个很好的代码规范,可以在我们日常中借鉴;

缺点:其中的正确用户名、密码、主页、主页用户名展示,主页退出按钮等都是GPT擅自揣测的且没有提前说明,如果给不懂脚本的人来看是会被忽悠住;

用例脚本太少了,和上面一大堆的用例完全不是一起来的;用例没有引入什么标准框架,比较落后;selenium的定位写法也比较落后,最新的版本中这种写法是会报错的;

脚本没有分层概念,不能直接复用到现有的成熟框架里。

总结:代码还不能完全落地,仍然需要人来完善,但作为开个头来说还是不错的。

然后,我继续更新问题让其用unittest来重写,以便测试GPT能做到的极限。

import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class LoginTestCase(unittest.TestCase):

    def setup(self):
        self.driver = webdriver.executable_path='/path/to/chromedriver')
        self.driver.get('http://Logout/')
    
    def tearDown(self):
        self.driver.quit()
    
    def test_invalid_credentials(self):
        # 测试无效用户名和密码
        invalid_usernane = "fakeuser"
        invalid_password = "fakepass"
        username_input = self.driver.find_element_by_name('username')
        password_input = self.driver.find_element_by_name('password')
        submit_button = self.driver.find_element_by_css_selector("button[type='submit']")
        username_input.send_keys(invalid_username)
        password_input.send_keys(invalid_password)
        submit_button.click()
        
        # 检查错误消息是否正确显示
        error_msg = self.driver.find_element_by_css_selector('.alert-danger').text
        self.assertIn("用户名或密码不正确',error_msg)


    def test_valid_credentials(self):
        # 测试正确数据
        valid_username='testuser'
        valid_password='testpass'
    
        username_input = self.driver.find_element_by_name('username')
        password_input = self.driver.find_element_by_name('password')
        submit_button = self.driver.find_element_by_css_selector('button[type="subnit"]')
        username_input.clear()
        username_input.send_keys(valid_username)
        password_input.clear()
        password_input.send_keys(valid_password)
        submit_button.click()
        
        # 验证是否成功跳转到主页
        self.assertEqual(self.driver.current_url,"http://example/")
        
        # 验证是否显示用户信息
        user_info = self.driver.find_element_by_css_selector('.user-info').text
        self.assertIn(valid_username, user_info)
     def test_remember_me(self):
        # 测试是否记住用户名和密码
        valid_username ='testuser'
        valid_password='testpass'
        username_input = setf.driver.find_element_by_name('username')
        password_input = self.driver.find_element_by_name('password')
        remember_me_checkbox = self.driver.find_eLement_by_id('remember_me')
        submit_button = self.driver.find_element_by_css_selector("button[type='submit']")

        username_input.clear()
        username_input.send_keys(valid_username)
        password_input.clear()
        password_input.send_keys(valid_password)
        remember_me_checkbox.cLick()
        submit_button.click()

        # 验证是否已记住用户名和密码
        self.driver.get('http://example/")
        username_input = setf.driver.find_element_by_name('username')
        password_input = self.driver.find_element_by_name('password')

        self.assertEqual(usernane_input.get_attribute("value"),valid_usernane)
        self.assertEqual(password_input.get_attribute("value"),valid_password)



再来分析以上脚本,优点:使用了uniitest框架;增加了一条测试记住的用例;初始化的代码写在了setup可以保证每条用例的低耦合;缺点:数量,场景等仍然远远不足,且没有使用任何高级的写法,没有考虑时间等待等异常风险。 然后我再次提高询问水准,看看其代码程度,代码比较重复度高,截取一些关键点和新的部分:

import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class LoginTestCase(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
        self.driver.get('http:/example/')
    def tearDown(self):
        self.driver.quit()
    def test_invalid_credentials(self):
        # 测试无效用户名和密码
    def test_valid_credentials(self):
        # 测试正确凭据
    def test_remember_me(self):
        # 测试是否记住用户名和密码
    def test_empty_credentials(self):
        # 测试空用户名和密码
    def test_long_credentials(self):
        # 测试过长的用户名和密码
    def test_lockout_after_failed_attempts(self):
        # 测试多次失败登录后账户锁定
        invalid_username = 'testuser'
        invalid_password = 'wrongpass'
        username_input, password_input, submit_button = self._get_login_elements()
        for _ in range(3):
            ...
        # 检查账户是否被锁定
        error_msg = self.driver.find_element_by_css_selector('.alert-danger').text
        self.assertIn('您的账户已被锁定', error_msg)

    def _get_login_elements(self):
        # 获取登录表单元素
        username_input = self.driver.find_element_by_name('username')
        password_input = self.driver.find_element_by_name('password')
        remember_me_checkbox = self.driver.find_element_by_id('remember-me')
        submit_button = self.driver.find_element_by_css_selector('button[type="submit"]')
        return username_input, password_input, remember_me_checkbox, submit_button
if __name__ == '__main__':
    unittest.main()


继续点评:

优点:用例条数增多,如果继续追问下去,应该还可以增加;有了初级page-object模式的影子,元素定位独立出来了;

缺点:代码冗余,没有充分利用好用例规程和并发线程,浪费了很多执行时间。仍然没有考虑到一些网络延迟,卡顿等异常风险的处理。尚无数据驱动和关键字驱动概念。

然后我们继续升级提问文案,让其并发一下:

def test_login(self):
    #使用多个数据组合测试登录功能
    test_data=
    [
        ('username':'testuser','password':"testpass",'expected_uri':"http://example/",'expected_text':"欢迎testuser"},
        ('username':"fakeuser','password':"fakepass",'expected_error':"用户名或密码不正确"},
        ('username':'','password':"",'expected_error':"请输入用户名"}
    [
    threads = []
    for data in test_data:
        thread = threading.Thread(target=self._perform_login, args=(data,))
        thread.start()
        threads.append(thread)
    for thread in threads:
        thread.join()
def _perform_login(self,data):
    #执行单次登录操作
    username_input,password_input,submit_button=self._get_login_elements()
    
    username_input.clear()
    username_input.send_keys(data['username'])
    password_input.clear()
    password_input.send_keys(data['password'])
    submit_button.click()
    
    if 'expected_error' in data:
        error_msg = self.driver.find_element_by_css_selector('.alert-danger').text
        self.assertIn(data['expected_error'],error_msg)
    else:
        self.assertEqual(data['expected_url'],self.driver.current_url)
        self.assertIn(data['expected_text'],self.driver.page_source)


点评:

优点:上述代码,使用了thread库进行多线程并发;巧妙的初步运用了数据驱动的概念,不但用户名密码是不同的,连每次的提示语和url都进行了断言;初步运用了关键字驱动,来让每个线程自动判断自身的断言目的。而po模式的影子仍然存在;

缺点:多线程的运用没有进行系统的封装,存在较大风险和局限;用例的内容结构比较单一,之前复杂的如测试浏览器记住用户密码等无法参与到这个并发中;线程是按照用例作为基本单位,对需要前后文关联的多用例是无法实现的,(所以需要在线程和用例之间制作新的中间层作为单位比较好);数据分离仍然没有实现。

继续优化提问,看看结果:(代码仍然简化,只留下关键行)

class LoginPage:
    def __init__(self, driver):
        self.driver = driver
    def load(self):
        self.driver.get('http:/t/')
    def login(self, username, password, remember_me):
        # 输入用户名和密码
        username_input, password_input, remember_me_checkbox, submit_button = self._get_login_elements()
        ...
        # 点击“登录”按钮
    def get_error_message(self):

        return error_msg
    def get_user_info(self):
        return user_info
    def _get_login_elements(self):
        # 获取登录表单元素
        return username_input, password_input, remember_me_checkbox, submit_button

class LoginTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
        self.login_page = LoginPage(self.driver)
    def tearDown(self):
        self.driver.quit()
    def test_valid_login(self):
        # 测试正确凭据登录
        test_data = {'username': 'testuser', 'password': 'testpass', 'remember_me': True}
        self.login_page.load()
        self.login_page.login(test_data['username'], test_data['password'], test_data['remember_me'])
        # 验证是否成功跳转到主页并显示用户信息
    def test_invalid_login(self):
        # 测试无效凭据登录
    def test_empty_username(self):
        # 测试空用户名登录

class LoginKeywordTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
    def tearDown(self):
        self.driver.quit()
    def test_valid_login(self):
        # 测试正确凭据登录
        test_data = {'username': 'testuser', 'password': 'testpass', 'remember_me': True}
        self._perform_login(test_data)
        # 验证是否成功跳转到主页并显示用户信息
    def test_invalid_login(self):
        # 测试无效凭据登录
        test_data = {'username': 'fakeuser', 'password': 'fakepass', 'expected_error': '用户名或密码不正确'}
        self._perform_login(test_data)
        # 检查错误消息是否正确显示
    def test_empty_username(self):
        # 测试空用户名登录
         ......
        


点评:

优点:增加了关键字驱动,数据驱动,po模式,并发等高级用法。

缺点:各种高级用法割裂严重,并没有融合到一起去实现,而是单纯的写了好几个独立的类demo。

总结:代码直接运行起来还是会有很多问题,需要大量人工矫正。同样在连续的对话中,也需要测试同学自身对代码和框架建设的理解,才能挖掘更深一步GPT更多的价值,否则首次发问的答案目前不能提供更多参考。

功能测试阶段

前期准备测试用例,现在开始执行测试,日常工作测试验证预期的三板斧呢?看页面,翻日志,查数据库。

于是,继续找他编写SQL,查看日志,

增加查询条件再问试试

对于融入执行测试阶段呢,以上发问感觉像有了屠龙刀,但还没掌握对应的功法,他带给我们的回答只是用屠龙刀在砍树,整理问题思路的时间,以刚入门的测试同学的能力都足以完成基础SQL的编写。

4、总结

想要让chatGPT产出有效的回答,而不是对你say sorry需要遵循以下四个原则:

  • 提问清晰:尽可能清晰的、完整的描述问题
  • 简明扼要:尽量使用简单的语言和简洁的句子来表达问题,目前很多免费插件对描述字数都有限制
  • 单一提问:请一个一个的问,而不是把所有问题放在一个问题
  • 不要提供敏感信息:不要在问题中提供任何个人敏感信息

从上述实践可以看到,GPT会帮助你实现一些细节和底层,开发过程我们需要更加注重表层应用和交互使用,日常中有不错的点子和设计,但是没足够的时间去亲力亲为的实现,大量的重复建设代码在浪费自己的精力,有了GPT理论上可以短时间内实现爆炸输出。在测试流程的应用,目前我还在初步探索阶段,是否能对团队测试工作提效,还需要进一步的研究,后续会陆续补充,欢迎大家线上线下随时交流。

作者:京东物流 刘红妍

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

与【ChatGPT-应用篇】基于chatGPT覆盖测试过程的初步探索相似的内容:

【ChatGPT-应用篇】基于chatGPT覆盖测试过程的初步探索

ChatGPT如此火爆之势,作为测试人员对此也颇为好奇,简单的人机对话有哪些可以帮助我们测试工作呢?本文主要谈从测试视角,结合测试流程来看chatGPT的应用。

介绍ChatGPT:基于GPT-3.5的强大自然语言处理工具

ChatGPT是一个基于GPT-3.5架构的自然语言处理工具,它具有文本生成、文本分类、对话生成等多种能力。作为一种强大的自然语言处理工具,ChatGPT可以应用于智能客服、智能问答、内容创作等多个领域。如果您对ChatGPT感兴趣,可以通过关注本公众号了解更多信息,并体验基于ChatGPT的小程序提供的智能聊天和问答服务。

开源项目分享:ChatGPT 控制台聊天应用

开源项目分享:ChatGPT 控制台聊天应用 分享一个我最近完成的一个小应用,一个ChatGPT 的控制台聊天应用,大家都在搞AI,我也来玩一玩,顺便分享到社区,有兴趣的小伙伴可以去我的github主页下载体验。 项目简介 ChatGPT 控制台聊天应用 基于.NET8实现,一键拥有你的私人 Cha

基于ChatGPT用AI实现自然对话

1.概述 ChatGPT是当前自然语言处理领域的重要进展之一,通过预训练和微调的方式,ChatGPT可以生成高质量的文本,可应用于多种场景,如智能客服、聊天机器人、语音助手等。本文将详细介绍ChatGPT的原理、实战演练和流程图,帮助读者更好地理解ChatGPT技术的应用和优势。 2.内容 在当今快

基于ChatGPT的API的C#接入研究

今年开年,最火的莫过于ChatGPT的相关讨论,这个提供了非常强大的AI处理,并且整个平台也提供了很多对应的API进行接入的处理,使得我们可以在各种程序上无缝接入AI的后端处理,从而实现智能AI的各种应用。ChatGPT的API可以在前端,以及一些后端进行API的接入,本篇随笔主要介绍基于ChatGPT的API的C#接入研究。

ChatGPT小型平替之ChatGLM-6B本地化部署、接入本地知识库体验

本文期望通过本地化部署一个基于LLM模型的应用,能让大家对构建一个完整的应用有一个基本认知。包括基本的软硬环境依赖、底层的LLM模型、中间的基础框架及最上层的展示组件,最终能达到在本地零编码体验的目的。

ChatGPT搭建AI网站实战

1.概述 ChatGPT是一款基于GPT-3.5架构的大型语言模型,它能够进行自然语言处理和生成对话等任务。作为一款智能化的聊天机器人,ChatGPT有着广泛的应用场景,如在线客服、智能助手、个性化推荐等。今天笔者给大家分享一下如何使用ChatGPT的API模型快速搭建一个AI网站。 2.内容 在实

Seal AppManager v0.2 发布:进一步简化应用部署体验

经过近3个月的研发,Seal AppManager v0.2 已正式发布。 Seal AppManager 是一款基于平台工程理念的应用统一部署管理平台,于今年4月首次推出。在上一版本中,我们已经释出**集成 ChatGPT 简化服务模板代码生成、云成本可视化、动态环境管理**等功能,通过降低基础设

聊聊Transformer和GPT模型

本文基于《生成式人工智能》一书阅读摘要。感兴趣的可以去看看原文。 可以说,Transformer已经成为深度学习和深度神经网络技术进步的最亮眼成果之一。Transformer能够催生出像ChatGPT这样的最新人工智能应用成果。 ## 序列到序列(seq2seq) Transformer能实现的核心

AI推理实践丨多路极致性能目标检测最佳实践设计解密

摘要:基于CANN的多路极致性能目标检测最佳实践设计解密。 本文分享自华为云社区《基于CANN的AI推理最佳实践丨多路极致性能目标检测应用设计解密》,作者: 昇腾CANN 。 当前人工智能领域,最热门的无疑是以ChatGPT为代表的各种“新贵”大模型,它们高高在上,让你无法触及。但在人们的日常生活中