《Python编程:从入门到实战》(第2版)学习笔记 第11章 测试代码
【写在前面】为进一步提高自己的python代码能力,打算把几本经典书籍重新过一遍,形成系统的知识体系,同时适当记录一些学习笔记,我尽量及时更新!先从经典的《Python编程:从入门到实战》书籍开始吧。有问题欢迎在评论区讨论,互相学习,good good study,day day up!上一章《Python编程:从入门到实战》(第2版)学习笔记 第10章 文件和异常(下)介绍了文件和异常【分为上和下两篇】,这章介绍如何编写测试代码。
【特别说明】这是第二版的《Python编程:从入门到实战》,书本的Python版本是3.7.2,我自己运行代码的环境是3.7.0,不同Python版本的功能不同。
编写函数或类时,还可为其编写测试。通过测试,可确定代码面对各种输入都能够按要求的那样工作。在程序中添加新代码时,也可对其进行测试,确认不会破坏程序既有的行为。程序员都会犯错,因此每个程序员都必须经常测试其代码,在用户发现问题前找出它们。
在本章中将学习:使用Python模块unittest来测试代码,编写测试用例,核实一系列输入都将得到预期的输出。可以看到测试通过和未通过分别是什么样子,还将知道如果未通过如何有助于改进代码。而且将学习如何测试函数和类,并将知道该为项目编写多少个测试。
11.1 测试函数
要学习测试,必须有要测试的代码。下面的函数接受名和姓并返回整洁的姓名:
name_function.py
>>> def get_formatted_name(first, last):
>>> """生成整洁的姓名"""
>>> full_name = f"{first} {last}"
>>> return full_name.title()
为核实get_formatted_name() 像期望的那样工作,编写一个程序names.py使用该函数:
names.py
>>> from name_function import get_formatted_name #从name_function.py中导入函数
>>> print("Enter 'q' at any time to quit.")
>>> while True:
>>> first = input("\nPlease give me a first name: ")
>>> if first == 'q':
>>> break
>>> last = input("Please give me a last name: ")
>>> if last == 'q':
>>> break
>>> formatted_name = get_formatted_name(first, last)
>>> print(f"\tNeatly formatted name: {formatted_name}.")
这个程序用户可输入一系列名和姓,并看到格式整洁的姓名:
Enter 'q' at any time to quit.
Please give me a first name: janis
Please give me a last name: joplin
Neatly formatted name: Janis Joplin.
Please give me a first name: bob
Please give me a last name: dylan
Neatly formatted name: Bob Dylan.
Please give me a first name: q
上述输出无误。现在要修改get_formatted_name() ,使其能够处理中间名,要确保不破坏这个函数处理只含有名和姓的姓名的方式。可在每次修改后都进行测试:输入像Janis Joplin这样的姓名,运行程序names.py。这很繁琐。Python有一种自动测试函数输出的高效方式,对get_formatted_name() 进行自动测试,就能始终确信当提供测试过的姓名时,该函数都能正确工作。
11.1.1 单元测试和测试用例
Python标准库中的模块unittest 提供了代码测试工具。单元测试用于核实函数的某个方面没有问题。测试用例是一组单元测试,它们核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。全覆盖的测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。对大型项目进行全覆盖测试可能很难。通常,最初只要针对代码的重要行为编写测试,等项目被广泛使用时再考虑全覆盖。
11.1.2 可通过的测试
我们先看创建测试用例的语法,在创建测试用例之后,再添加针对函数的单元测试 。要为函数编写测试用例,先导入模块unittest和要测试的函数,再创建一个继承unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。
下面测试用例只包含一个方法,检查函数get_formatted_name() 在给定名和姓时能否正确工作:
test_name_function.py
>>> import unittest #导入模块unittest
>>> from name_function import get_formatted_name #导入要测试的函数
>>> class NamesTestCase(unittest.TestCase): #创建一个类,必须继承unittest.TestCase 类
>>> """测试name_function.py"""
>>> def test_first_last_name(self):
>>> """能正确处理Janis Joplin这样的姓名吗?"""
>>> formatted_name = get_formatted_name('janis', 'joplin')
>>> self.assertEqual(formatted_name, 'Janis Joplin')
>>> if __name__ == '__main__':
>>> unittest.main()
方法test_first_last_name() 核实只有名和姓的姓名能否被正确格式化。运行test_name_function.py时,所有以test_打头的方法都将自动运行。在这个方法中,调用了要测试的函数,同时使用了unittest 类最有用的功能之一:断言方法,该方法核实得到的结果是否与期望的结果一致。代码行self.assertEqual(formatted_name, 'Janis Joplin')的意思:“将formatted_name 的值与字符串'Janis Joplin'比较。如果它们相等,那么万事大吉;如果不相等,就给出提示!”
注意很多测试框架都会先导入测试文件再运行。导入文件时,解释器将在导入的同时执行它。if __name__ == '__main__'代码检查特殊变量__name__ (在程序执行时设置的)。
- 如果这个文件作为主程序执行,变量__name__ 被设置为'__main__' ,调用unittest.main() 来运行测试用例
- 如果这个文件被测试框架导入,变量__name__ 的值不是'__main__' ,因此不会调用unittest.main()
运行test_name_function.py输出如下:
. #该句点表明有一个测试通过
----------------------------------------------------------------------
Ran 1 test in 0.000s #Python运行了一个测试,消耗的时间不到0.001秒
OK #表明所有单元测试都通过
11.1.3 未通过的测试
测试未通过时结果什么样呢?修改get_formatted_name() ,使其能够处理中间名,但无法正确处理像Janis Joplin这样只有名和姓的姓名。
下面是get_formatted_name() 的新版本,它要求通过一个实参指定中间名:
name_function.py
>>> def get_formatted_name(first, middle, last):
>>> """生成整洁的姓名"""
>>> full_name = f"{first} {middle} {last}"
>>> return full_name.title()
这次运行程序test_name_function.py时,输出如下:
E #只有一个字母E 指出测试用例中有一个单元测试导致了错误
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase) #NamesTestCase 中的test_first_last_name() 导致了错误
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_name_function.py", line 8, in test_first_last_name
formatted_name = get_formatted_name('janis', 'joplin')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'
----------------------------------------------------------------------
Ran 1 test in 0.000s #运行了一个单元测试
FAILED (errors=1) #指出整个测试用例未通过,运行该测试用例时发生了一个错误
测试用例包含众多单元测试时,知道哪个测试未通过至关重要。traceback指出函数调用get_formatted_name('janis', 'joplin') 有问题,因为缺少一个必不可少的位置实参。
11.1.4 测试未通过时怎么办
测试未通过意味着编写的新代码有错,应修复导致测试不能通过的代码。
在本例中,get_formatted_name() 以前只需要名和姓两个实参,但现在要求名、中间名和姓。新增的中间名参数是必不可少的。就这里而言,最佳的选择是让中间名变为可选的。这样测试又能通过了,而且也可以接受中间名。在函数定义中将形参middle 移到形参列表末尾,默认值为一个空字符串:
name_function.py
>>> def get_formatted_name(first, last, middle=''):
>>> """生成整洁的姓名"""
>>> if middle:
>>> full_name = f"{first} {middle} {last}"
>>> else:
>>> full_name = f"{first} {last}"
>>> return full_name.title()
再次运行test_name_function.py:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
现在,测试用例通过。
11.1.5 添加新测试
get_formatted_name() 又能正确处理简单的姓名后,我们再编写一个测试,测试包含中间名的姓名。在NamesTestCase 类中再添加一个方法:
test_name_function.py
>>> --snip--
>>> class NamesTestCase(unittest.TestCase):
>>> """测试name_function.py"""
>>> def test_first_last_name(self):
>>> --snip--
>>> def test_first_last_middle_name(self):
>>> """能正确处理像Wolfgang Amadeus Mozart这样的姓名吗?"""
>>> formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
>>> self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')
>>> if __name__ == '__main__':
>>> unittest.main()
注意新的方法必须以test_ 打头,这样才会在运行test_name_function.py时自动运行。这个方法名清楚地指出测试的是get_formatted_name() 的哪个行为。可以在TestCase 类中使用很长的方法名,而且必须是描述性的。这些方法由Python自动调用,根本不用编写调用它们的代码。
再次运行test_name_function.py时,两个测试都通过了:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
11.2 测试类
之前是针对单个函数的测试,下面来编写针对类的测试。
11.2.1 各种断言方法
Python在unittest.TestCase 类中提供了很多断言方法。前面说过,断言方法检查你认为应该满足的条件是否确实满足。如果该条件确实满足,可以确信程序行为没有错误;如果并不满足,Python将引发异常。
表11-1描述了6个常用的断言方法。使用这些方法可核实返回的值等于或不等于预期的值,返回的值为 True 或 False ,以及返回的值在列表中或不在列表中。只能在继承unittest.TestCase 的类中使用这些方法。
表11-1 unittest模块中的断言方法
11.2.2 一个要测试的类
类的测试与函数的测试相似,大部分是测试类中方法的行为。下面看一个帮助管理匿名调查的类:
survey.py
>>> class AnonymousSurvey:
>>> """收集匿名调查问卷的答案"""
>>> def __init__(self, question):
>>> """存储一个问题,为存储答案做准备"""
>>> self.question = question
>>> self.responses = [] #空列表用于存储答案
>>> def show_question(self):
>>> """显示调查问卷"""
>>> print(self.question)
>>> def store_response(self, new_response):
>>> """存储单份调查答卷"""
>>> self.responses.append(new_response)
>>> def show_results(self):
>>> """显示收集到的所有答卷"""
>>> print("Survey results:")
>>> for response in self.responses:
>>> print(f"- {response}")
有了表示调查的实例后,使用show_question() 来显示其中的问题,使用store_response() 来存储答案并使用show_results() 来显示调查结果。为证明AnonymousSurvey 类能够正确工作,编写一个使用它的程序:
language_survey.py
>>> from survey import AnonymousSurvey
>>> # 定义一个问题,并创建一个调查
>>> question = "What language did you first learn to speak?"
>>> my_survey = AnonymousSurvey(question)
>>> # 显示问题并存储答案
>>> my_survey.show_question()
>>> print("Enter 'q' at any time to quit.\n")
>>> while True:
>>> response = input("Language: ")
>>> if response == 'q':
>>> break
>>> my_survey.store_response(response)
>>> # 显示调查结果
>>> print("\nThank you to everyone who participated in the survey!")
>>> my_survey.show_results()
这个程序使用问题question创建了一个AnonymousSurvey 对象。然后调用show_question() 来显示问题,并提示用户输入答案。在收到每个答案的同时将其存储起来。用户输入所有答案(输入q 要求退出)后,调用show_results() 来打印调查结果:
What language did you first learn to speak?
Enter 'q' at any time to quit.
Language: English
Language: Spanish
Language: English
Language: Mandarin
Language: q
Thank you to everyone who participated in the survey!
Survey results:
- English
- Spanish
- English
- Mandarin
AnonymousSurvey 类可用于进行简单的匿名调查。假设我们将它放在了模块survey 中,并想进行改进:让每位用户都可输入多个答案;编写一个方法,只列出不同的答案并指出每个答案出现了多少次;再编写一个类,用于管理非匿名调查。上述修改存在风险,可能影响AnonymousSurvey 类的当前行为。例如,允许每位用户输入多个答案时,可能会不小心修改处理单个答案的方式。要确认在开发这个模块时没有破坏既有行为,可以编写针对这个类的测试。
11.2.3 测试AnonymousSurvey 类
下面来编写一个测试,对AnonymousSurvey 类的行为的一个方面进行验证:如果用户面对调查问题只提供一个答案,这个答案也能被妥善地存储。为此,我们将在这个答案被存储后,使用方法assertIn() 来核实它确实在答案列表中:
test_survey.py
>>> import unittest
>>> from survey import AnonymousSurvey
>>> class TestAnonymousSurvey(unittest.TestCase):
>>> """针对AnonymousSurvey类的测试"""
>>> def test_store_single_response(self):
>>> """测试单个答案会被妥善地存储"""
>>> question = "What language did you first learn to speak?"
>>> my_survey = AnonymousSurvey(question)
>>> my_survey.store_response('English')
>>> self.assertIn('English', my_survey.responses)
>>> if __name__ == '__main__':
>>> unittest.main()
第一个测试方法验证:调查问题的单个答案被存储后,会包含在调查结果列表中。运行test_survey.py时,测试通过了:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
下面来核实当用户提供三个答案时,它们也将被妥善地存储。为此,在TestAnonymousSurvey 中再添加一个方法:
>>> import unittest
>>> from survey import AnonymousSurvey
>>> class TestAnonymousSurvey(unittest.TestCase):
>>> """针对AnonymousSurvey类的测试"""
>>> def test_store_single_response(self):
>>> --snip--
>>> def test_store_three_responses(self):
>>> """测试三个答案会被妥善地存储"""
>>> question = "What language did you first learn to speak?"
>>> my_survey = AnonymousSurvey(question)
>>> responses = ['English', 'Spanish', 'Mandarin']
>>> for response in responses:
>>> my_survey.store_response(response) #对其中每个答案调用store_response()
>>> for response in responses:
>>> self.assertIn(response, my_survey.responses) #确认每个答案都包含在my_survey.responses 中
>>> if __name__ == '__main__':
>>> unittest.main()
再次运行test_survey.py时,两个测试(针对单个答案的测试和针对三个答案的测试)都通过了:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
前述做法效果很好,但这些测试有些重复的地方。下面使用unittest的另一项功能来提高其效率。
11.2.4 方法setUp()
在前面test_survey.py中,我们在每个测试方法中都创建了一个AnonymousSurvey 实例,并在每个方法中都创建了答案。unittest.TestCase 类包含的方法setUp() 只需创建这些对象一次,能在每个测试方法中使用。在TestCase 类中,Python将先运行setUp() ,再运行各个以test_打头的方法。这样在每个测试方法中,都可使用在方法setUp() 中创建的对象。
下面使用setUp() 来创建一个调查对象和一组答案,供方法test_store_single_response() 和test_store_three_responses() 使用:
>>> import unittest
>>> from survey import AnonymousSurvey
>>> class TestAnonymousSurvey(unittest.TestCase):
>>> """针对AnonymousSurvey类的测试"""
>>> def setUp(self):
>>> """创建一个调查对象和一组答案,供使用的测试方法使用"""
>>> question = "What language did you first learn to speak?"
>>> self.my_survey = AnonymousSurvey(question) #创建一个调查对象存储在属性中
>>> self.responses = ['English', 'Spanish', 'Mandarin'] #创建一个答案列表
>>> def test_store_single_response(self):
>>> """测试单个答案会被妥善地存储"""
>>> self.my_survey.store_response(self.responses[0])
>>> self.assertIn(self.responses[0], self.my_survey.responses)
>>> def test_store_three_responses(self):
>>> """测试三个答案会被妥善地存储"""
>>> for response in self.responses:
>>> self.my_survey.store_response(response)
>>> for response in self.responses:
>>> self.assertIn(response, self.my_survey.responses)
>>> if __name__ == '__main__':
>>> unittest.main()
setUp()方法让两个测试方法都更简单,因为它们都不用创建调查对象和答案了。方法test_store_single_response() 核实self.responses 中的第一个答案self.responses[0] 被妥善地存储,而方法test_store_three_response() 核实self.responses 中的全部三个答案都被妥善地存储。
再次运行test_survey.py时,这两个测试也都通过了。如果要扩展AnonymousSurvey ,使其允许每位用户输入多个答案,这些测试将很有用。修改代码以接受多个答案后,可运行这些测试,确认存储单个答案或一系列答案的行为未受影响。
测试自己编写的类时,可在setUp() 方法中创建一系列实例并设置其属性,再在测试方法中直接使用这些实例。相比于在每个测试方法中都创建实例并设置其属性,这要容易得多。
注意 运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试通过时打印一个句点,测试引发错误时打印一个E ,而测试导致断言失败时则打印一个F 。这就是你运行测试用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。如果测试用例包含很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。
11.3 小结
在本章中,我们学习了:
- 如何使用模块unittest 中的工具来为函数和类编写测试
- 如何编写继承unittest.TestCase 的类,以及编写测试方法,以核实函数和类的行为符合预期
- 如何使用方法setUp() 来根据类高效地创建实例并设置其属性,并在类的所有测试方法中使用
测试是很多初学者不熟悉的主题。初学者并非必须为所有项目编写测试。然而参与工作量较大的项目时,你应该对自己所编写函数和类的重要行为进行测试。这样能够更加确定自己的工作不会破坏项目其他部分,从而自由地改进既有代码。如果不小心破坏了原来的功能,你马上就会知道,而且能够轻松地修复问题。比起等到不满意的用户报告bug后再采取措施,在测试未通过时采取措施要容易得多。
如果你在项目中包含了初步测试,将得到其他程序员的尊敬。他们不仅能够更得心应手地使用你编写的代码,也更愿意与你合作开发项目。如果要跟其他程序员开发的项目共享代码,就必须证明你编写的代码通过了既有测试,通常还需要为你添加的新行为编写测试。
通过多开展测试来熟悉代码测试过程。对于自己编写的函数和类,最好是编写针对其重要行为的测试。不过不要在项目早期试图编写全覆盖的测试用例,除非有充分的理由。
说明:记录学习笔记,如果错误欢迎指正!写文章不易,转载请联系我。
相关文章:

《Python编程:从入门到实战》(第2版)学习笔记 第11章 测试代码
【写在前面】为进一步提高自己的python代码能力,打算把几本经典书籍重新过一遍,形成系统的知识体系,同时适当记录一些学习笔记,我尽量及时更新!先从经典的《Python编程:从入门到实战》书籍开始吧。有问题欢…...

SpringBoot(1)基础入门
SpringBoot基础入门SpringBoot项目创建方式Idea创建SpringBoot官网创建基于阿里云创建项目手工搭建SpringBoot启动parentstarter引导类内嵌tomcat基础配置属性配置配置文件分类yaml文件yaml数据读取整合第三方技术整合JUnit整合MyBatis整合Mybatis-Plus整合DruidSpringBoot是由…...

利用Flow Simulation快速经济高效地解决传热难题
几乎一切事物都会经历某种程度的发热或冷却,而且对于许多产品来说,热管理已成为避免过度发热和实现功能正常运行的一个关键要求。能够有效解决传热问题的制造商将会在竞争中占有明显的优势。利用一个简单易用的流体分析应用程序 SOLIDWORKS Flow Simulat…...

揭开二维码背后的神秘面纱用二维码识别 API 就够了
写在前面 二维码(QR code)已经成为现代生活中不可或缺的一部分。二维码具有可靠性、快速识别、易于存储等优点,因此在广泛应用于支付、门票、社交网络、广告等方面。但是,对于大多数人来说,二维码背后的编码方式是完全…...

系统分析——系统构建最重要的一环
🌟所属专栏:信息系统分析与设计 🐔作者简介:rchjr——五带信管菜只因一枚 😮前言:该系列将持续更新信息系统分析与设计课程的相关学习笔记,欢迎和我一样的小白订阅,一起学习共同进步…...

第1-第20个高级shell程序
高级shell脚本 1.使用Shell脚本批量修改文件名 #!/bin/bash for fi lein$(ls*.txt) do mv $file${file%%.*}.md done2.统计一个文本文件中某个单词出现的次数 #!/bin/bashword"example" count0 whilereadline do forwin$line do if["$w""$word&qu…...

【致敬嵌入式攻城狮第2期活动预热征文】学习安排
文章目录「 致敬未来的攻城狮计划 」——学习计划前言学习计划🚗单片机理论实践🚗学业阅读计划「 致敬未来的攻城狮计划 」——学习计划 🚀🚀开启攻城狮的成长之旅!这是我参与的由 CSDN博客专家 架构师李肯和 瑞萨MCU …...

035:cesium加载KML文件,显示图形
第035个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载KML文件, 显示图形。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共83行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:https:/…...

随想录Day42--动态规划: 416. 分割等和子集(终于吃下01背包了)
今天只有1道题,属于动态规划的01背包问题的应用。首先理解一下动态规划的01背包问题。推荐一个视频,动态规划DP0-1背包,这是我认为讲得最为通透的。很多讲解动态背包问题的,一上来就画二维表格,遍历背包或者遍历容量&a…...

字节跳动软件测试岗,前两面过了,第三面被面试官吊打,结局我哭了
阎王易见,小鬼难缠。我一直相信这个世界上好人居多,但是也没想到自己也会在阴沟里翻船。我感觉自己被字节跳动的HR坑了。 在这里,我只想告诫大家,offer一定要拿到自己的手里才是真的,口头offer都是不牢靠的࿰…...

bitlocker 笔记
介绍 bitlocker是windows自带的磁盘加密工具,win10专业版是可以使用的,其他家庭版本可能没有这个功能。有点类似与wd security。 功能 加密磁盘,当磁盘物理丢失时,防止磁盘中的数据泄露。举个例子,移动硬盘被偷&…...

Linux 压缩与解压命令
一、常见的压缩文件扩展名 1、*.Z compress程序压缩的文件 2、*.gz gzip程序压缩的文件 3、.tar.gz tar程序打包的文件,其中经过gzip的压缩 4、.tar tar程序打包的数据,并没有压缩过 5、.bz2 bzip2程序压缩的文件 6、.tar.bz2 tar程序打包的文件&a…...

python global函数用法及常用的 global函数代码
Python中的 global函数是用于在程序中定义变量的函数,在我们实际的开发中,我们可能会用到 global函数来定义变量,但是我们在这里就不具体介绍它的用法了。 global函数定义变量的方法: global函数使用参数a来指定变量在程序中的地址…...

大数据学完好就业么
Python的普及与数据挖掘、人工智能和数值计算等领域的蓬勃发展相关,但同时也与普遍编程需求的增加有关。 Python应用领域广泛,意味着选择Python的同学在学成之后可选择的就业领域有很多,加上Python本身的优势,致使现在越来越多的…...

CASAtomic 原子操作详解
文章目录CAS&Atomic 原子操作详解什么是原子操作CAS相关原子操作类的使用AtomicIntegerAtomicIntegerArray更新引用类型原子更新字段类LongAdderCAS&Atomic 原子操作详解 什么是原子操作 Mysql事务中的原子性就是一个事务中执行的多条sql,要么同时成功&am…...

卷积神经网络(convolutional neural network, CNN)
卷积神经网络(convolutional neural network, CNN) 卷积神经网络(convolutional neural network, CNN),是一种专门用来处理具有类似网格结构的数据的神经网络。卷积网络是指那些至少在网络的一层中使用卷积运算来替代…...

kube-apiserver启动流程源码分析
1. 概述 KubeAPIServer 主要是提供对 API Resource 的操作请求,为 kubernetes 中众多 API 注册路由信息,暴露 RESTful API 并且对外提供 kubernetes service,使集群中以及集群外的服务都可以通过 RESTful API 操作 kubernetes 中的资源。 2…...

Scala基础(二)
单例对象(object) Scala的类中无法定义静态成员,即无static关键字。如何像Java一样表达类的静态成员变量、成员方法与静态代码块? Scala解决方案:单例对象 使用“object”关键字声明,可包含变量、方法与…...

Python 生产者消费者模型是什么?
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注! 作者| 慕课网精英讲师 朱广蔚 1. 简介 生产者和消费者问题是线程模型中的经典问题: 生产者和消费者共享同一个存储空间生产者往存储空间中添…...

手机银行评测系列:北京银行“京彩生活”7.0从用户视角出发,实现沉浸式体验重塑
易观:2023年3月28日,北京银行发布“京彩生活”APP 7.0版本,从旅程再造、特色金融、场景生态、平台联动、协同经营、体验管理和安全守护七大方面全面升级,从用户视角出发,重塑用户旅程,简化操作流程…...

ZJYC2023 浙江省大学生程序设计竞赛校内选拔赛部分题解 C J B L
ZJYC2023 浙江省大学生程序设计竞赛校内选拔赛部分题解 C J B L 难度分布: 签到:CJ Easy:BL Midium:IAGKFE Hard:DH 题解: 签到:CJ C - ^{-1} 参考代码: #include<bits/std…...

百科创建:7种有效的百科词条创建技巧
百科词条是互联网上最常见的知识信息资源之一,它们是人们查找信息的主要途径之一。创建一个高质量的百科词条并不是一件容易的事情,需要一些技巧和经验才能做到。下面是一些创建百科词条的技巧: 一、确保词条的独特性 在创建百科词条之前&…...

ThreeJS-dat.gui界面控制颜色、隐藏、位置(六)
下载组件dat.gui npm install dat.gui -S 引入组件 import * as dat from dat.gui //界面控制 代码: <template> <div id"three_div"> </div> </template> <script> import * as THREE from "three"; import {O…...

接口自动化测试,完整入门篇
目录 1. 什么是接口测试2. 基本流程3. 需求分析4. 用例设计5. 脚本开发6. 结果分析7. 完整脚本8. 参考资料1. 什么是接口测试 顾名思义,接口测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及…...

利用ControlNet重新定义你的AI姿势
利用ControlNet重新定义你的AI姿势 前段时间给大家分享了如何利用colab实现AI绘画自由,现在Stable Diffusion WebUI Colab TW又更新了不少新功能。最重要的是可以通过谷歌硬盘的快捷方式导入模型,极大的节省了谷歌硬盘容量。 众所周知,谷歌…...

中医药NER命名实体识别基于SPANNER方式
一个不知名大学生,江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion:2023.3.5 Last edited: 2023.3.5 导读 本文使用SPANNER方式实现对中医药进行实体识别,采用focal loss 进行优化。 本文章作用防止安静…...

Vue必掌握
目录 一、组件通信方式 二、v-if和v-for 三、生命周期 1、描述 2、setup和created谁先执行 3、setup中为什么没有beforeCreate和created 四、双向绑定 v-model 1、定义 2、本质,原理 3、好处 五、如何扩展一个组件 1、mixins 缺点 2、slot插槽 3、e…...

SSM部分
声明式事务 从之前的事务控制的代码中可以看出,是有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。 封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。 …...

【Springboot系列】Springboot接管所有Controller,magic-api源码阅读
系列文章地址:Spring Boot学习大纲,可以留言自己想了解的技术点 最近在项目中使用了一个第三方的包 magic-api,节省了很多的时间,整体来说就是只用写sql就好了,不用写service,controller那些,全部统一处理了。 具体的使用大家可以搜索下,网上到处都是,建议去官网看。…...

二、LED子系统数据结构详解
个人主页:董哥聊技术我是董哥,嵌入式领域新星创作者创作理念:专注分享高质量嵌入式文章,让大家读有所得!文章目录1、核心数据结构1.1 gpio_led_platform_data1.2 gpio_leds_priv1.3 gpio_led1.4 gpio_led_data1.5 led_…...