当前位置: 首页 > news >正文

Python接口自动化之unittest单元测试

以下主要介绍unittest特性、运行流程及实际案例。

一、单元测试三连问

1、什么是单元测试?
 

按照阶段来分,一般就是单元测试,集成测试,系统测试,验收测试。单元测试是对单个模块单个类或者单个函数进行测试。

  • 将访问接口的过程封装在函数里面;

  • 接口测试就变成了单元测试;

  • 单元测试就是通过传参,对某个模块、某个类、某个函数进行结果输出后验证的测试。

2、为什么要做单元测试?
 

1.单元测试之后,才是集成测试,单个的功能模块测试通过之后,才能把单个功能模块集成起来做集成测试,为了从底层发现bug,减少合成后出现的问题。

2.越早发现bug越好,否则问题累计到后期,如果做错了就要推倒重来,对于时间和人力成本来说非常耗费精力。

对于我们测试来说:单元测试是为了执行测试用例。

3、怎么做单元测试?
 

Python里有两个单元测试类:

1.Unittest(Python自带);

2.Pytest(下载安装);

前者多用于接口自动化项目用,后者多用于WEB自动化项目、APP自动化项目。

  

二、unittest模块说明

1、unittest简介
 

unittest是Python自带的单元测试框,具备编写用例组织用例执行用例输出报告等自动化框架的条件,可以用来作自动化测试框架的用例组织执行框架。

unittest框架的特性:

  • 提供用例组织与执行:当测试用例只有几条的时候可以不考虑用例的组织,但是当测试用例数量较多时,此时就需要考虑用例的规范与组织问题。unittest单元测试框架就是用来解决这个问题的。

  • 提供丰富的断言方法:既然是测试,就有一个预期结果和实际结果的比较问题。比较就是通过断言来实现,unittest单元测试框架提供了丰富的断言方法,通过捕获返回值,并且与预期值进行比较,从而得出测试通过与否。

  • 提供丰富的日志:每一个失败用例我们都希望知道失败的原因,所有用例执行结束我们有希望知道整体执行情况,比如总体执行时间,失败用例数,成功用例数。unittest单元测试框架为我们提供了这些数据。

2、unittest组成

unittest单元测试中最核心的四个部分是:TestCase(测试用例),TestSuite(测试套件),TestRunner(测试运行器),TestFixture(测试环境数据准备和清理)
1.TestCase(测试用例):一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程。包括测试前准备环境的搭建(setUp)、实现测试过程的代码(run),以及测试后环境的还原(tearDown)。单元测试(Unittest)的本质也就在这里,一个测试用例就是一个完整的测试单元,通过运行这个测试单元,可以对某一个功能进行验证。
 

2.TestSuite(测试套件):一个功能的验证往往需要多个测试用例,可以把多个测试用例集合在一起执行,这就产生了测试套件TestSuite的概念。TestSuite用来组装单个测试用例。可以通过addTest加载TestCase到TestSuite中,从而返回一个TestSuite实例。而且TestSuite也可以嵌套TestSuite。

3.TestLoader(测试用例加载器):用来加载TestCase到TestSuite中的,其中loadTestsFrom__()方法用于寻找TestCase,并创建它们的实例,然后添加到TestSuite中,返回TestSuite实例;

4.TextTestRunner(执行测试用例):用来执行测试用例,其中run(test)会执行TestSuite/TestCase中的run(result)方法,并将测试结果保存到TextTestResult实例中,包括运行了多少测试用例,成功多少,失败多少等信息;

5.Test Fixture(测试环境数据准备和清理):一个测试用例的初始化准备及环境还原,主要是setUp() 和 tearDown()方法;比如说在测试用例中需要访问数据库,那么可以在setUp()中建立数据库连接以及进行一些初始化,在tearDown()中清除在数据库中产生的数据,然后关闭连接。注意tearDown的过程很重要,要为以后的TestCase留下一个干净的环境。

3、unittest核心工作原理

unittest的静态类图:

大体流程:编写TestCase,由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,最后将运行的结果保存在TextTestResult中。

三、unittest单元测试

1、实现思路
 

1.导入unittest模块、 被测文件或者其中的类;

2.创建一个测试类,并继承unittest.TestCase方法;

3.重写setUp和tearDown方法(如果有初始化条件和结束条件)。若setup()成功运行,无论测试方法是否成功,都会运行tearDown ();

4.定义测试函数,函数名以test_开头,以识别测试用例;

5.调用unittest.main()方法运行测试用例;

6.用例执行后,需要判断用例是Pass还是Fail,可以用unittest.TestCase模块的:断言

断言就是比对预期结果。如果不加断言,没有结果对比,需要手动去检查运行的结果是否符合预期。

2、使用介绍
 

  1. 要想使用unittest单元测试框架,必须得先导入:import unittest

  2. 查看unittest源码;

import unittest
print(help(unittest))
 

从打印结果中提取出unittest简易的例子:

import unittest
class IntegerArithmeticTestCase(unittest.TestCase):def testAdd(self):  # test method names begin with 'test'self.assertEqual((1 + 2), 3)self.assertEqual(0 + 1, 1)def testMultiply(self):self.assertEqual((0 * 10), 0)self.assertEqual((5 * 8), 40)
if __name__ == '__main__':unittest.main()

四、unittest实例

1、TestCase(测试用例)
 

看了官方代码后,我们自己写个例子熟悉下,并总结出规律:

import unittest
class TestDemo(unittest.TestCase):# test_sub用例def test_sub(self):self.assertEqual(2-1,1)# test_add用例def test_add(self):self.assertEqual(2+1,3)
if __name__ == "__main__":# unittest.main()是运行主函数unittest.main(verbosity=2)

运行结果为:

test_add (__main__.TestDemo) ... ok
test_sub (__main__.TestDemo) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
 

接下来,我们来总结一些规律:

1.使用unittest前,需导入unittest框架。

2.TestDemo这个类必须继承unittest.TestCase,TestCase类,所有测试用例类继承的基类。

3.类内的方法必须以test开头,比如test_add。

4.断言:assertEqual用来断言预期结果和实际结果是否一致。当然unittest还包含很多其他断言方法,后面统一介绍。

5.用例执行顺序。在代码中test_sub方法写在test_add前,但实际,test_add比test_sub先运行。为什么呢?unittest执行测试用例,默认是根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。

6.verbosity是一个选项,表示测试结果的信息复杂度,有0、1、2 三个值。verbosity=0 : 你只能获得测试用例数总的结果;verbosity=1 (默认模式): 在每个成功的用例前面有个“.” 每个失败的用例前面有个 “F”;verbosity=2 (详细模式):测试结果会显示每个测试用例的所有相关的信息。

如下,在测试用例中写入断言:

import unittest
#测试MathMethod类
class TestMathMethod(unittest.TestCase):#编写测试用例def test_add_two_positive(self): #测试两个正数相加res=MathMethod(1,1).add()print("1+1的结果是:",res)self.assertEqual(2,res,"两个正数相加出错!") #断言def test_add_two_zero(self): #测试两个0相加res = MathMethod(0, 0).add()print("0+0的结果是:", res)self.assertEqual(0, res, "两个0相加出错!") #断言def test_add_two_negative(self): #测试两个负数相加res = MathMethod(-1, -1).add()print("-1+(-1)的结果是:", res)self.assertEqual(-2, res, "两个负数相加出错!") #断言
if __name__ == '__main__':unittest.main()

测试用例里面的setUp函数与tearDown函数的使用:

class TestMathMethod(unittest.TestCase):
def setUp(self):print("开始准备执行测试用例!")def tearDown(self):print("结束!")#编写测试用例
def test_add_two_positive(self): #测试两个正数相加res=MathMethod(1,1).add()print("1+1的结果是:",res)

 
  • setUp函数:初始化环境(执行每条用例之前,都要执行setUp函数下面的代码,每次都要执行);

  • tearDown函数:清洗环境(执行每条用例之后,都要执行tearDown函数下面的代码,每次都要执行);

  • setUp()、tearDown()是TestCase里的方法,写在测试类中,就是方法的重写。

  • 执行顺序是:setUp->testA->tearDown->setUp->testB>tearDown

2、TestSuit(测试集)

当测试用例全部写完,但是只想执行其中部分,可以使用TestSuit()来收集测试用例。

import unittest
from xxx import xxx      #测试用例的类
suite=unittest.TestSuit()
suite.addTest(测试用例的类("用例名称1"))    #用例名称用字符串的形式传入
suite.addTest(测试用例的类("用例名称2"))
suite.addTest(测试用例的类("用例名称3"))
.....

3、TestLoader(加载测试用例)
 

方式一:通过测试类来加载用例(loadTestsFromTestCase)

一次性加载测试用例类名1下的所有用例。

import unittestfrom xxx import xxx      #测试用例的类suite=unittest.TestSuit()loader=unittest.TestLoader()suite.addTest(loader.loadTestsFromTestCase(测试用例类名1))  #测试用例类名直接传入
 

方式二:通过测试类所在的模块加载用例(loadTestsFromModule)

一次性加载测试用例模块名下的所有用例。

import unittest
from xxx import xxx      #测试用例模块
suite=unittest.TestSuit()
loader=unittest.TestLoader()
suite.addTest(loader.loadTestsFromTestCase(测试用例模块名))   #测试用例模块名直接传入

4、生成测试报告
 

方式一:使用unittest自带的TextTestRunner生成测试报告(文本格式,不推荐使用)。

TextTestRunner是一个以文本形式展示测试结果的测试运行程序类

  • stream 输出报告的路径,默认输出控制台;

  • verbosity 控制输出报告的详细程度,从0-2,越来越详细;

方式二:使用第三方模块HTMLTestRunnerNew(生成HTML格式的测试报告,推荐使用)。

  • file:文件

  • verbosity:详细程度

  • title:标题

  • description:描述

  • tester:作者

with open("接口测试报告.html","wb") as file:runner = HTMLTestRunnerNew.HTMLTestRunner(stream=file,  verbosity=2,title="接口自动化测试报告",description="接口测试V1",tester="ITester软件测试小栈")runner.run(suite)

方式三:使用unittest.defaultTestLoader.discover() 模糊匹配。

import unittest
import HTMLTestRunnerNewall_testcases=unittest.defaultTestLoader.discover(contants.testcases_dir, pattern='test_*.py',top_level_dir=None) #利用上下文管理器自动关闭资源
with open(contants.reports_html,"wb+") as file:    #选择绝对路径,把文件打开,写进内容 (报告的文件名直接写在路径里面)runner=HTMLTestRunnerNew.HTMLTestRunner(stream=file,title="接口自动化测试报告",description="接口测试V1",tester="ITester软件测试小栈")runner.run(all_testcases)

总结:本文主要介绍单元测试,unittest模块特性、大致流程、源码及实战例子。

相关文章:

Python接口自动化之unittest单元测试

以下主要介绍unittest特性、运行流程及实际案例。 一、单元测试三连问 1、什么是单元测试? 按照阶段来分,一般就是单元测试,集成测试,系统测试,验收测试。单元测试是对单个模块、单个类或者单个函数进行测试。 将访…...

在亚马逊云科技Amazon SageMaker上部署构建聊天机器人的开源大语言模型

开源大型语言模型(LLM)已经变得流行起来,研究人员、开发人员和组织都可以使用这些模型来促进创新和实验。这促进了开源社区开展合作,从而为LLM的开发和改进做出贡献。开源LLM提供了模型架构、训练过程和训练数据的透明度&#xff…...

【51单片机】10-蜂鸣器

1.蜂鸣器的原理 这里的“源”不是指电源。而是指震荡源。 也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。 而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它。 有源蜂鸣器往往比无源的贵&#xff…...

26377-2010 逆反射测量仪 知识梳理

声明 本文是学习GB-T 26377-2010 逆反射测量仪. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了逆反射测量仪的术语和定义、结构与分类、技术要求、计量学特性、试验方法、检验规 则以及标志、包装、运输与贮存。 本标准适用于…...

css实现渐变电量效果柱状图

我们通常的做法就是用echarts来实现 比如 echarts象形柱图实现电量效果柱状图 接着我们实现进阶版,增加渐变效果 echarts分割柱形图实现渐变电量效果柱状图 接着是又在渐变的基础上,增加了背景色块的填充 echarts实现渐变电量效果柱状图 其实思路是一…...

FileManager/本地文件增删改查, Cache/图像缓存处理 的操作

1. FileManager 本地文件管理器,增删改查文件 1.1 实现 // 本地文件管理器 class LocalFileManager{// 单例模式static let instance LocalFileManager()let folderName "MyApp_Images"init() {createFolderIfNeeded()}// 创建特定应用的文件夹func cr…...

vue中使用富文本编辑器

vue中使用富文本编辑器&#xff08;wangEditor&#xff09; wangEditor官网地址&#xff1a;https://www.wangeditor.com/ 使用示例 <template><div class"app-container"><div class"box"><div class"editor-tool">&l…...

13.(开发工具篇github)如何在GitHub上上传本地项目

一:创建GitHub账户并安装Git 二:创建一个新的仓库(repository) 三、拉取代码 git clone https://github.com/ainier-max/myboot.git git clone git@github.com:ainier-max/myboot.git四、拷贝代码到拉取后的工程 五、上传代码 (1)添加所有文件到暂存...

vue3中状态适配

写一个函数&#xff0c;在函数中定义一个对象 用于存放键值对&#xff0c;最后返回指定状态所对应的的值&#xff0c;即对象[指定状态] 的 对象的值。 在模板中把状态传入 // vue3 setup语法糖中 const formatXXXState (xxxState)>{const stateMap {键1: 值1,键2: 值2,.…...

uniapp h5 端 router.base设置history后仍有#号

manifest.json文件设置&#xff1a; "h5": { "router": { "base": "./", "mode": "history" }, }按相对路径发行时路由模式强制为hash模式&#xff0c;不支持history模式&#xff08;两者相悖&#xff09;…...

上网行为监管软件(上网行为管理软件通常具有哪些功能)

在我们的日常生活中&#xff0c;互联网已经成为了我们获取信息、交流思想、进行工作和娱乐的重要平台。然而&#xff0c;随着互联网的普及和使用&#xff0c;网络安全问题也日益突出&#xff0c;尤其是个人隐私保护和网络行为的规范。在这个背景下&#xff0c;上网行为审计软件…...

C#中的for和foreach的探究与学习

一:语句及表示方法 for语句: for(初始表达式;条件表达式;增量表达式) {循环体 }foreach语句: foreach(数据类型 变量 in 数组或集合) {循环体 }理解 1.从程序逻辑上理解,foreach是通过指针偏移实现的(最初在-1位置,每循环一次,指针就便宜一个单位),而for循环是通...

【ES6知识】Promise 对象

文章目录 1.1 概述1.2 静态方法1.3 实例方法1.4 Promise 拒绝事件 1.1 概述 Promise 对象用于表示一个异步操作的最终完成&#xff08;或失败&#xff09;及其结果值。是异步编程的一种解决方案&#xff08;可以解决回调地狱问题&#xff09;。 一个 Promise 对象代表一个在这…...

【Git】配置SSH密钥实现Git操作免密

背景 在使用Git推送代码的时候&#xff0c;会默认需要输入密码。如果经常推送代码&#xff0c;那就需要经常输入密码&#xff0c;比较繁琐。所以Git也提供了免密登录的功能。 Git本身支持两种协议对远程Git仓库进行访问&#xff1a;HTTPS、SSH。两种方式有一定的区别&#xf…...

AI能给百融云带来什么?

一大堆有关ChatGPT的利好消息出现之后&#xff0c;市场的反应难得的跟投资者预期站在了一起&#xff0c;AIGC也终于有了跑赢CPO的苗头。二级市场的逻辑不用重复&#xff0c;毕竟AI已经炒了大半年&#xff0c;但有没有发现一个问题&#xff1f;就是在不知不觉中&#xff0c;AI应…...

AI创作系统ChatGPT商业运营版源码+AI绘画/支持GPT联网提问/支持Midjourney绘画+Prompt应用+支持国内AI提问模型

一、AI创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&am…...

vue.draggable拖拽,项目中三个表格互相拖拽的实例操作,前端分页等更多小技巧~

vue.draggable中文文档 - itxst.com官网在这里&#xff0c;感兴趣的小伙伴可以看看。 NPM或yarn安装方式 yarn add vuedraggable npm i -S vuedraggable UMD浏览器直接引用JS方式 <script src"https://www.itxst.com/package/vue/vue.min.js"></script&…...

400G DR4 QSFP-DD光模块:数据中心应用全攻略

在当今数字化时代&#xff0c;对于企业和供应商来说&#xff0c;高速数据传输至关重要。随着对更快数据传输的需求不断攀升&#xff0c;400G DR4 QSFP-DD光模块已经成为高速网络的最新解决方案。本文将全面介绍400G DR4 QSFP-DD光模块在数据中心应用中的优势和技术规范。 什么…...

自动驾驶:路径规划概述

自动驾驶&#xff1a;路径规划概述 全局路径规划Dijkstra算法A*算法RRT&#xff08;随机快速探索树&#xff09;算法PRM&#xff08;概率路线图&#xff09;算法 局部路径规划DWA&#xff08;动态窗口法&#xff09;算法TEB&#xff08;时间弹性带&#xff09;算法Lattice Plan…...

vlc将本地文件推流成ts实时流

推流 打开vlc &#xff0c;打开 媒体----打开网络串流 选择文件选项卡&#xff0c;打开本地文件 点击添加&#xff0c;选择本地的mp3文件 选择串流 点击下拉框&#xff0c;选择udp&#xff0c;点击右边的【添加】按钮 输入媒体流输出地址&#xff0c;点击【下一个】 选择正确的…...

C# 自定义控件库之Lable组合控件

1、创建类库 2、在类库中添加用户控件&#xff08;Window窗体&#xff09; 3、控件视图 4、后台代码 namespace UILib {public partial class DeviceInfoV : UserControl{public DeviceInfoV(){InitializeComponent();ParameterInitialize();}#region 初始化private void Par…...

解密防关联指纹浏览器:联盟营销领域的秘密武器

联盟营销在今天的数字化时代越来越受欢迎。然而&#xff0c;联盟营销也面临着一些挑战&#xff0c;其中之一就是账号关联问题。本文将介绍如何利用防关联指纹浏览器来提升联盟营销的效果和安全性。 一、什么是防关联指纹浏览器&#xff1f; 防关联指纹浏览器是一种工具&#…...

asp.net core mvc Razor +dapper 增删改查,分页(保姆教程)

说明&#xff1a;本demo使用sqlserver数据库&#xff0c;dapper orm框架 完成一张学生信息表的增删改查&#xff0c;前端部分使用的是Razor视图&#xff0c; Linq分页 HtmlHelper。&#xff08;代码随便写的&#xff0c;具体可以自己优化&#xff09; //实现效果如下&#xff0…...

网络安全——自学(黑客)方法

如果你想自学网络安全&#xff0c;首先你必须了解什么是网络安全&#xff01;&#xff0c;什么是黑客&#xff01;&#xff01; 1.无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面性&#xff0c;例如 Web 安全技术&#xff0c;既有 Web 渗透2.也有 Web 防…...

秋招算法岗,面试复盘

面试锦囊之面经分享系列&#xff0c;持续更新中 欢迎后台回复『面试』加入讨论组交流噢 楼主秋招主要投算法岗&#xff08;偏NLP方向&#xff09;和数据岗方向&#xff0c;下面分享我的一些面试经历。 一、科大讯飞&#xff08;NLP&#xff09; 简要介绍自己Python里面哈希表…...

AI类APP能做什么

AI类APP可以实现多种功能&#xff0c;涵盖了各种领域和用途。以下是一些常见的AI类APP示例以及它们主要实现的功能&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.语音助手&#xff08;Voice Assis…...

计算机毕业设计 基于SSM的垃圾分类管理系统(以医疗垃圾为例)的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

友思特案例|友思特 Ensenso 3D相机:汽车工业自动化的革命性力量

01 内容摘要 在竞争激烈的汽车行业&#xff0c;自动化生产至关重要。友思特 Ensenso 3D相机为汽车制造商提供了可靠的工具和技术支持&#xff0c;助力多个关键环节。它在汽车座位泡棉切割中提高精确度&#xff0c;降低浪费&#xff0c;提高生产效率&#xff1b;在汽车压铸零部…...

【5G PHY】物理层逻辑和物理天线的映射

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…...

MySQL如何优雅处理批量新增和更新?ON DUPLICATE KEY UPDATE用它!

场景&#xff1a;一张用户表user&#xff0c;此时我需要批量新增用户&#xff0c;如果用户已经存在了&#xff0c;则更新该条记录&#xff1b;如果用户不存在&#xff0c;则插入一条数据。 痛点&#xff1a;常规做法新增更新各写一个接口。而且是批量操作&#xff0c;比较繁琐&…...

湖南做网站/宁波网站推广代运营

1)贴图&#xff1a;<img src"图片地址">2)加入连接&#xff1a;<a href"所要连接的相关地址">写上你想写的字</a>3)在新窗口打开连接&#xff1a;<a href"相关地址" target"_blank">写上要写的字</a>消…...

北京网站首页排名公司/企业培训课程

心态炸裂 昨晚忙活到半夜照着攻略&#xff0c;一顿操作&#xff0c;中间虽然有几个小错误还都纠正过来了&#xff0c;成功搭建好了博客。结果今天下午想着去给博客换个好点的theme&#xff0c;结果照着一顿操作&#xff0c;各种报错&#xff0c;关键是我也不懂也找不到如何解决…...

做二手房的端口网站/下载百度网盘app

前言 在项目中频繁遇到数组、集合和泛型&#xff0c;在使用vue时&#xff0c;用到最多的是数组&#xff1b;在后台时使用最多的是泛型&#xff0c;有时还用到IList&#xff0c;下面来学习一下它们之间的关系。 正文 数组 概念 一组类型相同的有序数据&#xff0c;它是…...

b2b网站开发/2023年东莞疫情最新消息

我相信&#xff0c;有很多小伙伴在看到这篇文章时就有了很多问号&#xff1a;用vim&#xff1f;疯了吧&#xff1f;sublime不香吗&#xff1f;pycharm不香吗&#xff1f;jupyter notebook不香吗&#xff1f;我这可是最新版的windows 100操作系统诶&#xff0c;你要劝我回到Dos/…...

中山市 做网站/在线crm网站建站

如有错误&#xff0c;恳请指出。 文章目录1. MMDetection的安装2. MMDetection的使用2.1 官方demoImage推理Video推理Webcam推理2.2 实践测试OpenMMLad有一系列的开源算法库&#xff0c;包含分类&#xff0c;检测&#xff0c;分割等等计算机视觉的任务&#xff0c;这篇博客用来…...

2014做网站/最好的bt磁力搜索引擎

引用格式&#xff1a;刘振彬&#xff0c;危双丰&#xff0c;庞帆&#xff0c;等&#xff0e;基于单目及惯导的同步定位与建图方案&#xff3b;&#xff2a;&#xff3d;&#xff0e;测绘科学&#xff0c;&#xff12;&#xff10;&#xff12;&#xff10;&#xff0c;&#xf…...