unittest 测试框架的使用

news2024/12/24 20:48:43

文章目录

  • 1. unittest 框架解析
  • 2. 批量执行测试脚本
    • 1)构建测试套件
      • addTest() 方法
      • makeSuite() 方法
      • TestLoader() 方法
    • 2)用例的执行顺序
    • 3)忽略测试用例的执行
  • 3. unittest 断言
  • 4. HTML 报告生成
  • 5. 异常捕获与错误截图
  • 6. 数据驱动
    • 1)测试多个不同数据
    • 2)测试某个文件中的多组数据
      • txt 文件或者 csv 文件
      • JSON 文件

1. unittest 框架解析

unittest 是 python 的单元测试框架,主要有以下作用:

  • 提供测试用例的组织和执行: unittest 框架可以将成百上千条测试用例组织在一起进行执行
  • 提供丰富的比较方法: 再用例执行完成之后都需要将实际结果和预期结果进行比较(断言),从而断定用例是否通过,unittest 中提供了丰富的断言方法
  • 提供丰富的日志: 当测试用例执行失败会抛出清晰的失败原因,当所有的用例执行完成后会提供丰富的执行结果,执行时间、失败用例数、成功用例数等

unittest 中有四个很重要的概念: test fixturetest casetest suitetest runner

  • test fixture

    对一个测试用例环境的搭建和销毁,就是一个 fixture,通过重写 setUp() 方法和 tearDown() 方法来实现

    setUp() 方法可以进行测试环境的搭建,比如获取浏览器的驱动、设置测试 URL、连接数据库等操作

    tearDown() 方法及逆行环境的销毁,可以关闭浏览器、关闭数据库等

  • test case

    一个 test case 就是一个测试用例,即一个完整的测试流程,包括 setUp 方法、tearDown 方法以及完成测试过程的代码

  • test suite

    测试套件,test suite 用来将多个测试用例组装在一起

  • test runner

    在 unittest 框架中,通过 textTestRunner 类下的 run() 方法来执行测试用例或者测试套件

下面是一个使用了 unittest 框架的简单测试脚本

  • 脚本中的类必须继承 unittest.TestCase 类,之后这个类就是一个 TestCase
  • 每一个 TestCase 中都必须含有 setUp 方法和 tearDown 方法
  • 执行测试代码的方法必须以 “test_” 开头
  • unittest 中提供了 main 方法来执行本测试用例
from selenium import webdriver
import time
import unittest
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains


class bing(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://cn.bing.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    def test_search(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys("python")
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys(Keys.ENTER)
        time.sleep(3)

    def test_closeImg(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("id_sc").click()
        time.sleep(3)
        a = driver.find_element_by_xpath("//*[@id='qs_iotd_ctrl']/div/div[3]/div")
        ActionChains(driver).move_to_element(a).perform()
        time.sleep(3)
        a.click()
        time.sleep(3)


if __name__ == "__main__":
    unittest.main()

2. 批量执行测试脚本

1)构建测试套件

将多个测试用例组织起来形成一个 test suite 测试套件,就可以一次性执行多个测试用例

假设有如下两个测试用例:

testBing.py

from selenium import webdriver
import time
import unittest
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains


class bing(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://cn.bing.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    def test_search(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys("python")
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys(Keys.ENTER)
        time.sleep(3)

    def test_closeImg(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("id_sc").click()
        time.sleep(3)
        a = driver.find_element_by_xpath("//*[@id='qs_iotd_ctrl']/div/div[3]/div")
        ActionChains(driver).move_to_element(a).perform()
        time.sleep(3)
        a.click()
        time.sleep(3)


if __name__ == "__main__":
    unittest.main()

testBaidu.py

from selenium import webdriver
import time
import unittest
from selenium.webdriver.common.action_chains import ActionChains


class baidu(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    def test_search(self):
        url = self.url
        driver = self.driver
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("kw").send_keys("python")
        time.sleep(3)
        driver.find_element_by_id("su").click()
        time.sleep(3)

    def test_hao_search(self):
        url = self.url
        driver = self.driver
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_link_text("hao123").click()
        time.sleep(3)

    def test_baiduTranslation(self):
        url = self.url
        driver = self.driver
        driver.get(url)
        time.sleep(3)
        a = driver.find_element_by_link_text("更多")
        ActionChains(driver).move_to_element(a).perform()
        time.sleep(3)
        driver.find_element_by_xpath("//*[@id='s-top-more']/div[1]/a[1]").click()
        time.sleep(3)


if __name__ == '__main__':
    unittest.main()

unittest 中提供了多种方法来构建测试套件

addTest() 方法

TestSuite 类的 addTest 方法可以把不同的测试类中的测试方法组装带测试套件中,但是 addTest 方法一次只能把一个类中的一个方法添加到测试套件中

import unittest
from src_selenium.src_unittest import testBing
from src_selenium.src_unittest import testBaidu


def createSuite():
    # addTest
    suite = unittest.TestSuite()
    suite.addTest(testBing.bing("test_closeImg"))
    suite.addTest(testBing.bing("test_search"))
    suite.addTest(testBaidu.baidu("test_search"))
    suite.addTest(testBaidu.baidu("test_hao_search"))
    return suite

# 执行测试套件
if __name__ == '__main__':
    suite = createSuite()
    # verbosity 设置日志级别,2最高,0最低
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

makeSuite() 方法

makSuite 方法配合 addTest 方法可以实现一次将某个测试类中的所有测试方法添加到测试套件

只需要在 makeSuite 方法中传入测试类名即可

import unittest
from src_selenium.src_unittest import testBing
from src_selenium.src_unittest import testBaidu


def createSuite():
    # makeSuite
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(testBing.bing))
    suite.addTest(unittest.makeSuite(testBaidu.baidu))
    return suite

# 执行测试套件
if __name__ == '__main__':
    suite = createSuite()
    # verbosity 设置日志级别,2最高,0最低
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

TestLoader() 方法

TestLoader 方法的作用与 makeSuite 方法一样,都是将某个测试类中的所有测试方法添加到测试套件中

不同的是 TestLoader 不需要配合 addTest 使用,直接使用 unittest.TestLoader().loadTestsFromTestCase() 方法即可,

import unittest
from src_selenium.src_unittest import testBing
from src_selenium.src_unittest import testBaidu


def createSuite():
    # TestLoader
    suite1 = unittest.TestLoader().loadTestsFromTestCase(testBing.bing)
    suite2 = unittest.TestLoader().loadTestsFromTestCase(testBaidu.baidu)
    suite = unittest.TestSuite([suite1, suite2])
    return suite

# 执行测试套件
if __name__ == '__main__':
    suite = createSuite()
    # verbosity 设置日志级别,2最高,0最低
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

discover() 的应用

discover 方法可以将某个目录下的所有符合标准的脚本文件中的所有测试方法添加到测试套件中

使用 unittest.defaultTestLoader.discover() 方法,第一个参数填入某个目录的绝对路径,第二个参数填入标准文件名,testB*.py 则表示以 testB 开头的 python 文件,第三个参数表示测试模块的顶层目录,一版设置为 None 即可

import unittest
from src_selenium.src_unittest import testBing
from src_selenium.src_unittest import testBaidu


def createSuite():
   # discover 的应用
    discover = unittest.defaultTestLoader.discover("D:\\JAVA\\Python\\project\\src_selenium\\src_unittest", pattern="testB*.py", top_level_dir=None)
    print(discover)
    return discover

# 执行测试套件
if __name__ == '__main__':
    suite = createSuite()
    # verbosity 设置日志级别,2最高,0最低
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

2)用例的执行顺序

unittest 框架在执行多个测试方法时,会根据类名或者方法名的 ASCII 码顺序进行执行,即 0 ~ 9,A ~ Z,a ~ z

就测试方法来说,顺序是根据 “ test_ ” 后的单词进行排序

3)忽略测试用例的执行

如果在某一次测试中不需要执行某一个测试方法,就需要把这个测试方法忽略不执行,使用 @unittest.skip() 注解就可以完成,写入的参数会在控制台打印出

@unittest.skip("test_hao_search 被忽略")
def test_hao_search(self):
    url = self.url
    driver = self.driver
    driver.get(url)
    time.sleep(3)
    driver.find_element_by_link_text("hao123").click()
    time.sleep(3)

请添加图片描述

3. unittest 断言

对于每一个单独的测试用例来说,必然会有预期结果和实际结果,通过比对预期结果和实际结果就可以判断测试用例是否通过

反映到代码中就是断言,断言通过则会继续执行下面的代码,否则对应的测试方法就会停止或者生成错误信息,但不会影响其他测试方法的执行

unittest 中提供了丰富的断言方法

msg 参数为断言未通过时的提示语,可以自定义,也可以不写此参数

断言方法描述
assertEqual(arg1, arg2, msg=None)验证 “arg1== arg2” 是否通过
assertNotEqual(arg1, arg2, msg=None)验证 “arg1!= arg2” 是否通过
assertTrue(arg, msg=None)验证 “args 为 True” 是否通过
assertFalse(arg, msg=None)验证 “args 为 False” 是否通过
assertIs(arg1, arg2, msg=None)验证 “arg1 和 arg2 是同一个对象” 是否通过
assertNotIs(arg1, arg2, msg=None)验证 “arg1 和 arg2 不是同一个对象”是否通过
assertIsNone(arg, msg=None)验证 “arg 是 None” 是否通过
assertIsNotNone(arg, msg=None)验证 “arg 不是 None” 是否通过
assertIn(arg1, arg2, msg=None)验证 “arg1 是 arg2 的子串” 是否通过
assertNotIn(arg1, arg2, msg=None)验证 “arg1 不是 arg2 的子串” 是否通过
assertIsInstance(obj, cls, msg=None)验证 “obj 是 cls 的实例” 是否通过
assertNotIsInstance(obj, cls, msg=None)验证 “obj 不是 cls 的实例” 是否通过

断言用法小示例:

def test_search(self):
    driver = self.driver
    url = self.url
    driver.get(url)
    time.sleep(3)
    driver.find_element_by_id("sb_form_q").send_keys("python")
    time.sleep(3)
    driver.find_element_by_id("sb_form_q").send_keys(Keys.ENTER)
    time.sleep(3)
    print(driver.title)
    # 验证 “打开的网页 title 不是 ‘python - 搜索’” 是否通过
    self.assertNotEqual("python - 搜索", driver.title, msg="未打开页面")

未通过就会在控制台给出错误信息

请添加图片描述

4. HTML 报告生成

脚本执行完成之后,还需要生成一个测试报告,这里就可以使用 HTMLTestRunner.py 来生成 HTML 形式的测试报告

HTMLTestRunner.py 文件,下载地址: http://tungwaiyip.info/software/HTMLTestRunner.html

下载后将其放入 python 安装目录的 Lib 目录下

HTMLTestRunner 支持python2.7。python3可以参见http://blog.51cto.com/hzqldjb/1590802来进行修改。

import HTMLTestRunner
import os.path
import sys
import time
import unittest
from src_selenium.src_unittest import testBing
from src_selenium.src_unittest import testBaidu


def createSuite():
    # makeSuite
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(testBing.bing))
    suite.addTest(unittest.makeSuite(testBaidu.baidu))
    return suite

if __name__ == '__main__':
    # 创建一个存放 HTML 报告的文件夹
    curPath = sys.path[0]  # 获取当前文件的路径
    if not os.path.exists(curPath + "/result"):
        # 判断是否存在此文件夹,不存在则创建一个
        os.makedirs(curPath + "/result")

    # 用当前时间作为 HTML 报告的文件名
    now = time.strftime("%Y-%m-%d-%H%M%S", time.localtime(time.time()))  # 获取当前时间

    # 拼接报告地址
    fileName = curPath + "/result/" + now + "report.html"

    # 出报告
    with open(fileName, "wb") as f:
        runner = HTMLTestRunner.HTMLTestRunner(f, title="测试报告", description="用例执行情况", verbosity=2)
        suite = createSuite()
        runner.run(suite)

在测试套件的主函数中添加上述代码,就可以生成一个 HTML 报告并保存到指定位置

报告打开之后如下所示:

请添加图片描述

标红的就是未通过的用例,点击 fail 还会显示详细的错误信息

5. 异常捕获与错误截图

在用例执行时如果可以将错误现场自动截图,那么就会给我们定位错误带来方便

编写一个函数,函数的主要功能就是截图并且保存到指定位置,此函数不以 “test_” 开头,即不让 unittest 自动执行该函数,将异常捕获之后,只在需 expect 中调用即可

使用 webdriver 下的 get_screenshot_as_file() 方法进行截图并保存

def test_search(self):
    driver = self.driver
    url = self.url
    driver.get(url)
    time.sleep(3)
    driver.find_element_by_id("sb_form_q").send_keys("python")
    time.sleep(3)
    driver.find_element_by_id("sb_form_q").send_keys(Keys.ENTER)
    time.sleep(3)
    try:
        self.assertNotEqual("python - 搜索", driver.title)
    except:
        self.saveScreenshot(driver, "search.png")
        
        
        
def saveScreenshot(self, driver, filename):
    # 创建文件夹保存截图
    if not os.path.exists("./img"):
        os.makedirs("./img")

    # 使用时间作为文件名
    now = time.strftime("%Y-%m-%d-%H%M%S", time.localtime(time.time()))
    driver.get_screenshot_as_file("./img/" + now + "-" + filename)
    time.sleep(1)

异常被捕获之后就不会在控制台显示了,我们处理异常的方式是截图错误现场并保存起来

请添加图片描述

6. 数据驱动

前面我们所有的数据和用例都是写在一起的,但是如果想在同一个用例中测试多个不同数据,按照之前的方法就需要编写多个用例,但其实可以使用 ddt 数据驱动来完成,ddt 可以使一个用例测试多个数据

unittest 没有自带的数据驱动,所以我们需要使用 pip 另外下载 ddt 数据驱动

ddt 中常用的注解:

  • @ddt: 修饰测试类
  • @data: 修饰测试方法,参数是测试数据
  • @file_data: 修饰测试方法,参数是 JSON 文件名,以文件中的数据作为测试数据
  • @unpack: 当传递的数据是元组或者列表是,使用此注解修饰测试方法,ddt 就会自动将数据映射到参数上

1)测试多个不同数据

一个参数的多个不同值

使用 @ddt 参数修饰测试类,@data 注解修饰测试方法并传入参数的不同值,在方法的参数列表中添加一个参数作为本方法的测试参数

from ddt import ddt, data, unpack, file_data
from selenium import webdriver
import time
import unittest
from selenium.webdriver.common.keys import Keys


@ddt
class bing(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://cn.bing.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    
    # 分别测试 bing 搜索 python、java、rust
    @data("python", "java", "rust")
    def test_search(self, value):
        driver = self.driver
        url = self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys(value)
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys(Keys.ENTER)
        time.sleep(3)


if __name__ == "__main__":
    unittest.main()

多个参数的多个不同值

修饰的注解不变,变得只是 @data 注解中的数据,可以使用列表表示一组测试数据

需要注意的是:当有多个参数时,需要使用 @unpack 注解修饰测试方法以映射多个参数

如下形式表示两个参数的多组数据

@data([3, 2], [4, 3], [5, 3])

from selenium import webdriver
import time
import unittest
from ddt import data, ddt, file_data, unpack


@ddt
class baidu(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    @data(["python", "python_百度搜索"], ["java", "python_百度搜索"], ["rust", "python_百度搜索"])
    @unpack
    def test_search(self, value, expect_value):
        url = self.url
        driver = self.driver
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("kw").send_keys(value)
        time.sleep(3)
        driver.find_element_by_id("su").click()
        time.sleep(3)
        self.assertEqual(expect_value, driver.title, msg="网页未打开")

        

if __name__ == '__main__':
    unittest.main()

2)测试某个文件中的多组数据

txt 文件或者 csv 文件

同样使用使用 @data() 注解修饰测试方法,但是参数填入的是解析 txt/csv 文件的方法

需要注意的是:文件的开头一行必须是 data,后面每一行为一组数据,这是固定格式,如下所示

请添加图片描述

import csv

from selenium import webdriver
import time
import unittest
from selenium.webdriver.common.action_chains import ActionChains
from ddt import data, ddt, file_data, unpack


def get_txt(file_name):
    tmp_data = []
    with open("./data/" + file_name, "r") as f:
        readers = csv.reader(f, delimiter=",", quotechar="|")
        next(readers, None)
        for row in readers:
            rows = []
            for i in row:
                rows.append(i)
            tmp_data.append(rows)
        print(tmp_data)
        return tmp_data


@ddt
class baidu(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    @data(*get_txt("test_Baidu.txt"))
    @unpack
    def test_search(self, value, expect_value):
        url = self.url
        driver = self.driver
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("kw").send_keys(value)
        time.sleep(3)
        driver.find_element_by_id("su").click()
        time.sleep(3)
        self.assertEqual(expect_value, driver.title, msg="网页未打开")



if __name__ == '__main__':
    unittest.main(verbosity=2)

JSON 文件

使用 @file_data(json 文件名) 修饰测试方法即可调用 json 文件中的数据

import os.path

from ddt import ddt, data, unpack, file_data
from selenium import webdriver
import time
import unittest
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains


@ddt
class bing(unittest.TestCase):
    def setUp(self):
        print("------setUp------")
        self.driver = webdriver.Chrome()
        self.url = "https://cn.bing.com/"
        self.driver.maximize_window()
        time.sleep(3)

    def tearDown(self):
        print("------tearDown------")
        self.driver.quit()

    # @data("python", "java", "rust")
    @file_data("./data/test_Bing.json")
    def test_search(self, value):
        driver = self.driver
        url = self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys(value)
        time.sleep(3)
        driver.find_element_by_id("sb_form_q").send_keys(Keys.ENTER)
        time.sleep(3)


if __name__ == "__main__":
    unittest.main()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目测试报告】网页版博客系统 + online 好友聊天室

网页版博客系统 online 好友聊天室(项目介绍) 实现一个网页版的博客系统,提供了一个技术文章论坛,同时也提供了用户之间在线交流的平台。 网页博客系统支持以下核心功能: 用户注册、登录、注销功能(登录…

JAVAWeb11-服务器渲染技术 -JSP-02-EL表达式(会使用)

1. EL 表达式介绍 EL 表达式全称&#xff1a;Expression Language&#xff0c;是表达式语言EL 表达式主要是代替 jsp 页面的表达式脚本<%request.getAttribute("xx")%>EL 表达式输出数据时&#xff0c;比 jsp 的表达式脚本简洁EL 表达式基本语法&#xff1a; …

HAL库版FreeRTOS(下)

目录 FreeRTOS 事件标志组FreeRTOS 事件标志组简介FreeRTOS 事件标志组相关API 函数FreeRTOS 事件标志组实验功能设计软件设计下载验证 FreeRTOS 任务通知FreeRTOS 任务通知简介任务通知的优势任务通知的缺点 FreeRTOS 任务通知相关API 函数 FreeRTOS 事件标志组 事件标志组与…

【Leetcode】241. 为运算表达式设计优先级

241. 为运算表达式设计优先级&#xff08;中等&#xff09; 解法一&#xff1a;分治法 对于这道题&#xff0c;加括号其实就是决定运算次序&#xff0c;所以我们可以把加括号转化为&#xff0c;「对于每个运算符号&#xff0c;先执行处理两侧的数学表达式&#xff0c;再处理此…

提高APP安全性的必备加固手段——深度解析代码混淆技术

APP 加固方式 Android APP 加固是优化 APK 安全性的一种方法&#xff0c;常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码&#xff1a; 使用 ProGuard 工具可以对代码进行混淆&#xff0c;使得反编译出来的代…

makefile语法解析

gcc语法简介 gcc (-c) hello.c world.c -o main-c表示只编译不链接 -o目标文件 此外&#xff0c;还有-I&#xff08;大写的I&#xff09;表示给gcc添加自定义的头文件的路径 -L表示给gcc添加额外的搜索库的路径 -g选项的意义是“生成调试信息&#xff0c;该程序可以被调试器调…

【Java入门合集】第五章抽象类和接口(二)

博主&#xff1a;命运之光 专栏&#xff1a;JAVA入门 学习目标 1.了解什么是抽象类&#xff0c;什么是接口&#xff1b; 2.掌握抽象类和接口的定义方法&#xff1b; 3.理解接口和抽象类的使用场景&#xff1b; 4.掌握多态的含义和用法&#xff1b; 5.掌握内部类的定义方法和使用…

【Hive实战】Hive元数据存储库数据增多的分析

Hive元数据存储库数据增多的分析 2023年5月8日 文章目录 Hive元数据存储库数据增多的分析问题新增Hive相关的DDL操作创建Hive库库授权到用户 创建Hive表 内部表非分区表表授权到用户一级分区表二级分区表分桶表分桶排序表 查询指令核心表分析表关系图表以库表为主以hive表为主以…

人人都可用的ChatGPT,Edge浏览器-免费ChatGPT保姆级教程!非常详细!

人工智能大浪潮已经来临&#xff0c;对于ChatGPT&#xff0c;我觉得任何一个玩互联网的人&#xff0c;都应该重视起来&#xff0c;用起来。但是国内使用需要解决科学上网、注册、收费等繁琐问题。 所以&#xff0c;今天这篇文章就来推荐一个插件&#xff0c;无需任何繁琐操作&…

第一次省赛团队训练 - BAPC 2022 Pre(DAPC 2022)

B (2). Bubble-bubble Sort [ 提交记录 ] [ 问题 3462 ] 时间限制: 2000MS 空间限制: 256MB 结果评判: 文本对比 正确/提交: 7 (5) / 15 官方标签: 用户标记: 题目描述 Bubbles! As a fanatical supporter of the Bubbles Are Perfect Creatures movement, you have ac…

第8章 未执行缓存的强制清理操作导致显示异常解决方案

1 异常产生原因&#xff1a; 由于未为Role实体定义相就的缓存强制销毁器类&#xff1a;Services.Customers.Caching.RoleCacheEventConsumer,从而导致Services.Events.EventPublisher.PublishAsync<TEvent>(TEvent event)中的 consumers实例为0,如下图所示&#xff1a; 2…

深入理解移动端布局:Viewport与设备像素比

在移动端开发中&#xff0c;了解和掌握不同设备的布局特点是非常重要的。本文将介绍两个关键概念&#xff1a;Viewport 和设备像素比&#xff08;DPR&#xff09;&#xff0c;帮助你更好地理解移动端布局。 一、什么是 Viewport&#xff1f; Viewport 是用户在浏览器中可见的网…

JS知识点(包括原型,原型对象,数据类型,数据类型的检测)

目录 1、JavaScript有哪些数据类型&#xff0c;它们的区别&#xff1f; 2、基本数据类型和引用数据类型地区别&#xff1a; 3、数据类型检测的方式有哪些: 4、判断数组的方式有那些&#xff1f; 5、null和undefined区别&#xff1a; 6、为什么typeOf null得到object而不是n…

22个提升生产力的工具推荐,稳了

子曰&#xff1a;工欲善其事&#xff0c;必先利其器。 本文给大家推荐22个提高生产力的工具&#xff0c;总有一款符合你的需求。&#x1f604;&#x1f604;&#x1f604; 提高生产效率工具推荐 滴答清单/Todoist文件检索利器&#xff1a;Everything文件管理软件-Allen Explor…

基于SpringBoot的大学生租房系统

背景 大学生租房系统设计的目的是建立一个高效的平台&#xff0c;采用简洁高效的Java语言与Mysql数据库等技术&#xff0c;设计和开发了本大学生租房系统设计。该系统主要实现了用户和房主通过系统注册用户&#xff0c;登录系统后能够编辑自己的个人信息、查看首页&#xff0c…

【电子学会】2023年03月图形化三级 -- 猫猫的儿童节

猫猫的儿童节 儿童节到了&#xff0c;给小猫绘制一个七彩的气球。 1. 准备工作 &#xff08;1&#xff09;保留小猫角色&#xff1b; &#xff08;2&#xff09;选择“Button2”角色&#xff0c;添加文字“开始”&#xff1b; &#xff08;3&#xff09;默认白色背景。 2…

有人抱怨Android找不到工作,有人却收到了好几个Offer~

不知不觉&#xff0c;往年常说的面试黄金季就这样过去了&#xff0c;相信现在很多人都会抱怨说&#xff0c;现在是市场岗位缩水裁员季。有人抱怨&#xff0c;自然也有人喜悦&#xff0c;有失业人群在&#xff0c;自然就业人群也有&#xff0c;有人想找一份合理工作很难&#xf…

C高级(day1)

作业: 初始工作路径不在家目录下&#xff0c;在不切换路径的情况下&#xff0c;在家目录下创建一个subdir目录&#xff0c;在subdir这个目录下&#xff0c;创建subdir1和subdir2&#xff0c;并且把/etc/passwd拷贝到subdir1中&#xff0c;把/etc/group文件拷贝到subdir2中&…

David Silver Lecture 5: Model-Free Control

1 Introduction 1.1 内容 上一章是对一个unknown MDP进行value function的预测&#xff0c;相当于policy evaluation。这一章是对unknown MDP找到一个最优的policy&#xff0c; optimise value function. 1.2 On and Off-Policy Learning On-policy learning learn on the…

[oeasy]python0050_动态类型_静态类型_编译_运行

动态类型_静态类型 回忆上次内容 上次了解了 帮助文档的 生成 开头的三引号注释 可以生成 帮助文档文档 可以写成网页 python3 本身 也有 在线的帮助手册 目前的程序 提高了 可读性 有什么方法 可以让程序 更可读么&#xff1f;&#x1f914; 变量名 首先 在变量名上想办…