appium自动化框架综合实践

结合前面的元素寻找、操作、unittest测试框架,搭建一个完整的自动化框架。本篇旨在框架设计、单机用例执行、输出报告,下篇继续实践Bat批处理执行测试、多设备并发测试。

框架功能

  • 数据配置
  • 日志输出
  • 截图处理
  • 基础功能封装(公共方法,查找元素)
  • 业务功能
  • 数据驱动
  • 测试用例封装
  • 断言处理和报告输出

测试需求

测试环境

  • win10
  • appium 1.17.1
  • weixin
  • 真机

测试用例

登录场景1.用户名 xxx 密码 xxx (登录成功)

登录场景2.用户名 xxx 密码 xxx (登录失败)

框架设计

 
  1. ​现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。

  2. 如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受

  3. 可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛

  4. 分享他们的经验,还会分享很多直播讲座和技术沙龙

  5. 可以免费学习!划重点!开源的!!!

  6. qq群号:680748947【暗号:csdn11】

代码实现

1.日志输出

  1. # -*- coding:utf-8 -*-

  2. # __author__ = "Cc"

  3. import logging

  4. import time

  5. class OutputLog:

  6. critical = logging.CRITICAL # 级别最高,什么也不输出

  7. fatal = logging.FATAL

  8. error = logging.ERROR

  9. warning = logging.WARNING

  10. info = logging.INFO

  11. debug = logging.DEBUG

  12. @classmethod

  13. def output_log(cls, log_level=debug):

  14. my_logging = logging.getLogger(__name__)

  15. my_logging.setLevel(log_level)

  16. if not my_logging.handlers:

  17. local_time = time.localtime()

  18. file_name1 = time.strftime('%Y-%m-%d', local_time)

  19. file_name2 = r"Logging\\"

  20. file_name = file_name2 + file_name1 + ".log"

  21. file_handler = logging.FileHandler(file_name, "a", encoding="utf-8") # 输出日志到磁盘文件

  22. file_handler.setLevel(log_level)

  23. formatter = logging.Formatter("%(asctime)s--%(levelname)s--%(process)d--"

  24. "%(thread)d--%(threadName)s--%(funcName)s--%(lineno)d--%(lineno)d : %(message)s")

  25. file_handler.setFormatter(formatter)

  26. my_logging.addHandler(file_handler)

  27. return my_logging

遇到的问题和解决方法

举个调用的例子:

 
  1. OutputLog.output_log().debug("==============开始测试,连接手机==============")

  2. OutputLog.output_log().debug("==============第二次调用==============")

上面代码,第一行日志输出只输出了一次,第二行输出了两次,原因是我在一开始实现时,每次调用都会重新创建一个handles,使用完后没有删除,同一log对象有多个handles,日志会重复输出,所以我在创建handles前先加以判断:if not my_logging.handlers,如果存在则不重新创建了。

2.设备初始化

2.1设备信息

保存设备信息在devices.yaml中,可以通过修改此文件,修改设备信息。

  1. oppo_findx_pro:

  2. appActivity: com.tencent.mm.ui.LauncherUI

  3. appPackage: com.tencent.mm

  4. autoGrantPermissions: true

  5. automationName: UiAutomator2

  6. chromeOptions:

  7. androidProcess: com.tencent.mm:toolsmp

  8. chromedriverExecutable: C:\Users\v_yddchen\Desktop\chromedriver_win32 77.0\chromedriver.exe

  9. deviceName: dd

  10. noReset: false

  11. platFormVersion: 10

  12. platformName: Android

  13. resetKeyboard: true

  14. udid: 648d4f29

  15. unicodeKeyboard: true

  16. oppo_reno:

  17. appActivity: com.tencent.mm.ui.LauncherUI

  18. appPackage: com.tencent.mm

  19. autoGrantPermissions: true

  20. automationName: UiAutomator2

  21. chromeOptions:

  22. androidProcess: com.tencent.mm:toolsmp

  23. chromedriverExecutable: C:\Users\v_yddchen\Desktop\chromedriver_win32 77.0\chromedriver.exe

  24. deviceName: df93a63a

  25. noReset: false

  26. platFormVersion: 9

  27. platformName: Android

  28. resetKeyboard: true

  29. udid: df93a63a

  30. unicodeKeyboard: true

2.2 初始化

初始化操作

  1. # 初始化设备

  2. # -*- coding:utf-8 -*-

  3. # __author__ = "Cc"

  4. from appium import webdriver

  5. import yaml

  6. from OutputLog import OutputLog

  7. from login import Login

  8. import time

  9. class InitDevices:

  10. def __init__(self, file_name, device_name):

  11. self.file_name = file_name

  12. self.device_name = device_name

  13. def read_devices(self):

  14. """

  15. 获取设备信息

  16. :return:

  17. """

  18. try:

  19. OutputLog.output_log().debug("尝试获取设备信息")

  20. with open(self.file_name, 'r', encoding='utf-8') as f:

  21. all_devices = yaml.safe_load(f.read())

  22. except IOError:

  23. OutputLog.output_log().error("设备文件读取错误")

  24. else:

  25. msg = str(all_devices[self.device_name])

  26. OutputLog.output_log().debug(msg)

  27. return all_devices[self.device_name]

  28. def init_devices(self, device_info):

  29. """

  30. 初始化设备

  31. :param device_info:

  32. :return:

  33. """

  34. return webdriver.Remote("http://localhost:4723/wd/hub", device_info)

  35. if __name__ == "__main__":

  36. OutputLog.output_log().debug("==============开始测试,连接手机==============")

  37. devices_object = InitDevices('devices.yaml', 'oppo_findx_pro')

  38. devices_info = devices_object.read_devices()

  39. devices = devices_object.init_devices(devices_info)

  40. OutputLog.output_log().debug("连接成功") # 连接成功,开始找元素

  41. file_name = 'screenshots/' + '测试' + '.png'

  42. devices.find_element_by_android_uiautomator('new UiSelector().textMatches("(.*)录")')

  43. devices.get_screenshot_as_file(file_name)

  44. devices.implicitly_wait(5)

  45. login_els = Login(devices)

  46. time.sleep(2)

  47. time.sleep(2)

3.获取测试数据

3.1 数据准备

3.2 读取数据

 
  1. # 读取测试数据

  2. # -*- coding:utf-8 -*-

  3. # __author__ = "Cc"

  4. import csv

  5. class ReadData:

  6. def __init__(self, file_name):

  7. self.file_name = file_name

  8. def read_data(self):

  9. """

  10. 注意文件不能有中文,否则会报错

  11. :return: 二维数组data

  12. """

  13. with open(self.file_name, 'r', encoding='utf-8') as f:

  14. csv_reader = csv.reader(f)

  15. head = next(csv_reader)

  16. # print(head)

  17. data = [[]]

  18. if len(data):

  19. data.clear() # 如果没有这一步,data会存在一个空值

  20. for data1 in csv_reader:

  21. data.append(data1)

  22. else:

  23. for data1 in csv_reader:

  24. data.append(data1)

  25. # print(data)

  26. return data

  27. if __name__ == "__main__":

  28. re = ReadData("login_msg.csv")

  29. re.read_data()

4.公共方法

寻找元素的公共方法的封装

 
  1. # 基类,查找元素

  2. # -*- coding:utf-8 -*-

  3. # __author__ = "Cc"

  4. from appium.webdriver import webdriver

  5. from selenium.webdriver.common.by import By

  6. from OutputLog import OutputLog

  7. class BaseFindEl:

  8. def __init__(self, devices):

  9. """

  10. 传入设备

  11. :param devices:

  12. """

  13. self.devices = devices

  14. def find_el_by_text(self, **kw):

  15. """

  16. 根据传入text时关键字参数的名称,决定调用text的哪一个方法

  17. :param kw: 查找元素的text

  18. :return: 返回找到的元素

  19. """

  20. if 'text' in kw:

  21. text = kw['text']

  22. path = 'new UiSelector().text("{}")'.format(text)

  23. return self.devices.find_element_by_android_uiautomator(path)

  24. elif 'textContains' in kw:

  25. text = kw['textContains']

  26. path = 'new UiSelector().textContains("{}")'.format(text)

  27. return self.devices.find_element_by_android_uiautomator(path)

  28. elif 'textStarsWith' in kw:

  29. text = kw['textStarsWith']

  30. path = 'new UiSelector().textStarsWith("{}")'.format(text)

  31. return self.devices.find_element_by_android_uiautomator(path)

  32. elif 'textMatches' in kw:

  33. text = kw['textMatches']

  34. path = 'new UiSelector().textMatches("{}")'.format(text)

  35. return self.devices.find_element_by_android_uiautomator(path)

  36. else:

  37. OutputLog.output_log().error("没有匹配到查找方法")

  38. def find_el_by_class_name(self, **kw):

  39. """

  40. 根据传入的className查找元素

  41. :param kw: className

  42. :return: 找到的元素

  43. """

  44. if 'className' in kw:

  45. text = kw['className']

  46. path = 'new UiSelector().className("{}")'.format(text)

  47. return self.devices.find_element_by_android_uiautomator(path)

  48. elif 'classNameContains' in kw:

  49. text = kw['classNameContains']

  50. path = 'new UiSelector().classNameContains("{}")'.format(text)

  51. return self.devices.find_element_by_android_uiautomator(path)

  52. else:

  53. OutputLog.output_log().error("没有匹配到查找方法")

  54. def find_el_by_resource_id(self, **kw):

  55. """

  56. 根据传入的resourceId查找元素

  57. :param kw:

  58. :return:

  59. """

  60. if 'resourceId' in kw:

  61. text = kw['resourceId']

  62. path = 'new UiSelector().resourceId("{}")'.format(text)

  63. return self.devices.find_element_by_android_uiautomator(path)

  64. elif 'resourceIdMatches' in kw:

  65. text = kw['resourceIdMatches']

  66. path = 'new UiSelector().resourceIdMatches("{}")'.format(text)

  67. return self.devices.find_element_by_android_uiautomator(path)

  68. else:

  69. OutputLog.output_log().error("没有匹配到查找方法")

  70. def find_el_by_multi_values(self, **values):

  71. """

  72. 组合多个属性

  73. :param values:

  74. :return:

  75. """

  76. pass

5.业务功能

  1. # 查找登录界面所有的元素

  2. # -*- coding:utf-8 -*-

  3. # __author__ = "Cc"

  4. from BaseFindEl import BaseFindEl

  5. from selenium.common.exceptions import NoSuchElementException

  6. from selenium.common.exceptions import TimeoutException

  7. from selenium.webdriver.support.ui import WebDriverWait

  8. from OutputLog import OutputLog

  9. class Login(BaseFindEl):

  10. def __init__(self, devices):

  11. BaseFindEl.__init__(self, devices)

  12. def login(self, text="登录"):

  13. """

  14. 点击登录

  15. :param text:

  16. :return:

  17. """

  18. self.devices.implicitly_wait(3)

  19. try:

  20. btn = self.find_el_by_text(text=text)

  21. except NoSuchElementException:

  22. msg = "错误:没有找到{}控件".format(text)

  23. OutputLog.output_log().error(msg)

  24. else:

  25. OutputLog.output_log().debug("进入到登录界面")

  26. btn.click()

  27. def sign_in(self, text="注册"):

  28. """

  29. :param text: 注册

  30. :return:

  31. """

  32. self.devices.implicitly_wait(3)

  33. try:

  34. btn = self.find_el_by_text(text=text)

  35. except NoSuchElementException:

  36. msg = "错误:没有找到{}控件".format(text)

  37. OutputLog.output_log().error(msg)

  38. else:

  39. OutputLog.output_log().debug("进入到注册界面")

  40. btn.click()

  41. def switch_to_username(self, text_contains="用微信号"):

  42. """

  43. :param text_contains: 切换到微信号/QQ号登录

  44. :return:

  45. """

  46. try:

  47. btn = self.find_el_by_text(textContains=text_contains)

  48. except NoSuchElementException:

  49. msg = "错误:没有找到{}控件".format(text_contains)

  50. OutputLog.output_log().error(msg)

  51. else:

  52. OutputLog.output_log().debug("切换到微信号输入界面")

  53. btn.click()

  54. def user_edit(self, text_contains="请填写微信号"):

  55. """

  56. 寻找账号输入框

  57. :param text_contains:

  58. :return: 账号阿输入edit

  59. """

  60. try:

  61. username_edit = self.find_el_by_text(textContains=text_contains)

  62. except NoSuchElementException:

  63. msg = "错误:没有找到{}控件".format(text_contains)

  64. OutputLog.output_log().error(msg)

  65. else:

  66. OutputLog.output_log().debug("找到了账号输入编辑框")

  67. return username_edit

  68. def pwd_edit(self, text_contains="请填写密码"):

  69. """

  70. 寻找账号输入框

  71. :param text_contains:

  72. :return: 账号阿输入edit

  73. """

  74. try:

  75. pwd_edit = self.find_el_by_text(textContains=text_contains)

  76. except NoSuchElementException:

  77. msg = "错误:没有找到{}控件".format(text_contains)

  78. OutputLog.output_log().error(msg)

  79. else:

  80. OutputLog.output_log().debug("找到了账号输入编辑框")

  81. return pwd_edit

  82. def input_msg(self, user_name, pwd):

  83. """

  84. 输入信息

  85. :param user_name: 账号名称

  86. :param pwd: 密码

  87. :return:

  88. """

  89. name_edit = self.user_edit()

  90. name_edit.clear()

  91. pwd_edit = self.pwd_edit()

  92. pwd_edit.clear()

  93. name_edit.send_keys(user_name)

  94. pwd_edit.send_keys(pwd)

  95. def find_toast(self, text="正在"):

  96. text_1 = "//*[contains(@text,'{}')]".format(text)

  97. toast = WebDriverWait(self.devices, 5, 0.00000001).until(lambda x: x.find_element_by_xpath(text_1))

  98. return toast.text

  99. def login_fail(self, screenshots_nam):

  100. """

  101. 处理登录失败的弹窗

  102. :param screenshots_nam: 截图保存的名称

  103. :return:

  104. """

  105. try:

  106. WebDriverWait(self.devices, 3).\

  107. until(lambda x: x.find_element_by_android_uiautomator('new UiSelector().textContains("密码错误")'))

  108. except TimeoutException:

  109. OutputLog.output_log().error("测试失败,没有找到登录失败的弹窗")

  110. file_name = 'screenshots/' + screenshots_nam + '.png'

  111. self.devices.get_screenshot_as_file(file_name)

  112. return 0

  113. else:

  114. OutputLog.output_log().debug("出现登录失败的弹窗")

  115. file_name = 'screenshots/' + screenshots_nam + '.png'

  116. self.devices.get_screenshot_as_file(file_name)

  117. self.find_el_by_text(text='确定').click()

  118. return 1

  119. def authorization_actions(self, screenshots_nam):

  120. try:

  121. WebDriverWait(self.devices, 3). \

  122. until(lambda x: x.find_element_by_android_uiautomator('new UiSelector().textMatches("(.*)权限申请")'))

  123. except TimeoutException:

  124. OutputLog.output_log().debug("没有出现权限申请弹窗")

  125. file_name = 'screenshots/' + screenshots_nam + '.png'

  126. self.devices.get_screenshot_as_file(file_name)

  127. else:

  128. OutputLog.output_log().debug("权限申请提示")

  129. file_name = 'screenshots/' + screenshots_nam + '.png'

  130. self.devices.get_screenshot_as_file(file_name)

  131. self.find_el_by_text(text='我知道了').click()

  132. def phone_authorization_actions(self, screenshots_nam, action='允许'):

  133. """

  134. :param screenshots_nam: 保存的截图

  135. :param action: 允许或者拒绝

  136. :return:

  137. """

  138. try:

  139. WebDriverWait(self.devices, 4). \

  140. until(lambda x: x.find_element_by_android_uiautomator('new UiSelector().textMatches("(.*)电话权限")'))

  141. except TimeoutException:

  142. OutputLog.output_log().debug("没有出现电话权限申请弹窗")

  143. file_name = 'screenshots/' + screenshots_nam + '.png'

  144. self.devices.get_screenshot_as_file(file_name)

  145. else:

  146. OutputLog.output_log().debug("电话权限申请提示")

  147. file_name = 'screenshots/' + screenshots_nam + '.png'

  148. self.devices.get_screenshot_as_file(file_name)

  149. self.find_el_by_text(text=action).click()

  150. def sd_card_authorization_actions(self, screenshots_nam, action='允许'):

  151. """

  152. :param screenshots_nam: 保存的截图

  153. :param action: 允许或者拒绝

  154. :return:

  155. """

  156. try:

  157. WebDriverWait(self.devices, 4). \

  158. until(lambda x: x.find_element_by_android_uiautomator('new UiSelector().textMatches("(.*)空间权限")'))

  159. except TimeoutException:

  160. OutputLog.output_log().debug("没有出现空间权限申请弹窗")

  161. file_name = 'screenshots/' + screenshots_nam + '.png'

  162. self.devices.get_screenshot_as_file(file_name)

  163. else:

  164. OutputLog.output_log().debug("空间权限申请提示")

  165. file_name = 'screenshots/' + screenshots_nam + '.png'

  166. self.devices.get_screenshot_as_file(file_name)

  167. self.find_el_by_text(text=action).click()

6.用例执行和报告输出

  1. # 执行用例

  2. # -*- coding:utf-8 -*-

  3. # __author__ = "Cc"

  4. from InitDevices import InitDevices

  5. from OutputLog import OutputLog

  6. from read_msg import ReadData

  7. from login import Login

  8. import unittest

  9. import time

  10. import os

  11. from selenium.webdriver.support.ui import WebDriverWait

  12. from selenium.common.exceptions import NoSuchElementException

  13. from selenium.common.exceptions import TimeoutException

  14. import HTMLReport

  15. class LoginUnittest(unittest.TestCase):

  16. devices_object = None

  17. devices = None

  18. data = None

  19. index0 = 0

  20. login_object = None

  21. def __init__(self, *args, **kwargs):

  22. """每个用例执行前,__init__都会执行一次"""

  23. super().__init__(*args, **kwargs)

  24. @classmethod

  25. def setUpClass(cls):

  26. """

  27. 初始化设备,读取测试数据,获取一个测试对象

  28. :return:

  29. """

  30. OutputLog.output_log().debug("==============开始测试,连接手机==============")

  31. cls.devices_object = InitDevices('devices.yaml', 'oppo_findx_pro')

  32. devices_info = cls.devices_object.read_devices()

  33. cls.devices = cls.devices_object.init_devices(devices_info) # 返回设备对象

  34. OutputLog.output_log().debug("连接成功") # 连接成功,开始操作

  35. cls.data = ReadData("login_msg.csv").read_data() # 获取登录数据

  36. cls.index0 = 0

  37. cls.login_object = Login(cls.devices)

  38. @classmethod

  39. def tearDownClass(cls):

  40. """

  41. devices.quit()

  42. :return:

  43. """

  44. # OutputLog.output_log().debug("测试结束")

  45. # cls.devices.quit()

  46. f = os.popen(r"adb shell dumpsys activity top | findstr ACTIVITY", "r") # 获取当前界面的Activity

  47. current_activity = f.read()

  48. f.close()

  49. print(current_activity) # cmd输出结果

  50. # 用in方法 判断一个字符串是否包含某字符

  51. appackage_name = 'com.ximalaya.ting.android'

  52. if appackage_name in current_activity:

  53. cls.drivers.quit()

  54. else:

  55. pass

  56. def setUp(self):

  57. """

  58. 每个用例执行前执行,这里切换登录方式

  59. :return:

  60. """

  61. LoginUnittest.login_object.login()

  62. time.sleep(1)

  63. LoginUnittest.login_object.switch_to_username()

  64. def tearDown(self):

  65. """

  66. 每个用例执行后执行,os.system("adb shell pm clear com.tencent.mm"),执行成功返回0

  67. :return:

  68. """

  69. time.sleep(1)

  70. if not os.system("adb shell pm clear com.tencent.mm"):

  71. # os.system("adb shell pm grant com.tencent.mm")

  72. OutputLog.output_log().debug("清除应用数据")

  73. LoginUnittest.index0 = LoginUnittest.index0 + 1

  74. time.sleep(3)

  75. # LoginUnittest.devices.start_activity('com.tencent.mm', '.ui.LauncherUI')

  76. os.system('adb shell am start com.tencent.mm/.ui.LauncherUI')

  77. else:

  78. OutputLog.output_log().debug("清除应用数据失败")

  79. time.sleep(2)

  80. # 测试登录失败

  81. def test_login_1(self):

  82. user_name = LoginUnittest.data[LoginUnittest.index0][0]

  83. pwd = LoginUnittest.data[LoginUnittest.index0][1]

  84. LoginUnittest.login_object.input_msg(user_name, pwd)

  85. msg = "登录信息" + user_name + pwd

  86. OutputLog.output_log().debug(msg)

  87. LoginUnittest.login_object.login() # 登录

  88. # try:

  89. # btn = WebDriverWait(LoginUnittest.devices, 7).\

  90. # until(lambda x: x.find_element_by_android_uiautomator('new UiSelector().text("通讯录")'))

  91. # except TimeoutException:

  92. # OutputLog.output_log().debug('登录失败')

  93. # self.assertEqual(1, 1, '登录失败')

  94. file_name = "test_login_1" + "登录失败"

  95. result = LoginUnittest.login_object.login_fail(file_name)

  96. self.assertEqual(result, 1, '失败')

  97. def test_login_2(self):

  98. user_name = LoginUnittest.data[LoginUnittest.index0][0]

  99. pwd = LoginUnittest.data[LoginUnittest.index0][1]

  100. LoginUnittest.login_object.input_msg(user_name, pwd)

  101. msg = "登录信息" + user_name + pwd

  102. OutputLog.output_log().debug(msg)

  103. LoginUnittest.login_object.login()

  104. file_name_1 = 'test_login_2' + '权限申请提醒'

  105. LoginUnittest.login_object.authorization_actions(file_name_1)

  106. file_name_3 = 'test_login_2' + '存储权限申请提醒'

  107. LoginUnittest.login_object.phone_authorization_actions(file_name_3)

  108. file_name_2 = 'test_login_2' + '电话权限申请提醒'

  109. LoginUnittest.login_object.phone_authorization_actions(file_name_2)

  110. try:

  111. btn = WebDriverWait(LoginUnittest.devices, 7).\

  112. until(lambda x: x.find_element_by_android_uiautomator('new UiSelector().text("通讯录")'))

  113. except TimeoutException:

  114. OutputLog.output_log().debug('登录失败')

  115. else:

  116. self.assertEqual(btn.text, '通讯录', '测试成功')

  117. if __name__ == '__main__':

  118. test_suite = unittest.TestSuite()

  119. tests = [LoginUnittest('test_login_1'), LoginUnittest('test_login_2')]

  120. test_suite.addTests(tests)

  121. # runner = unittest.TextTestRunner()

  122. runner = HTMLReport.TestRunner(

  123. report_file_name="login_reports",

  124. output_path="login_report",

  125. title="登录功能测试报告",

  126. description="测试登录功能",

  127. thread_count=1,

  128. thread_start_wait=0,

  129. tries=0,

  130. delay=0,

  131. back_off=1,

  132. retry=False,

  133. sequential_execution=True,

  134. lang="cn"

  135. )

  136. runner.run(test_suite)

7.执行结果

HTMLReport默认会输出一份.html报告文件和一份日志文件。只执行了两个用例,但是耗时0:2:28,代码还有待优化,Bat批处理命令执行,会不会对用例的执行效率有所提升呢?期待接下来的实践。

 

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java学习笔记NO.24

T1.完成理工超市系统的商品类及其子类的定义,实现“浏览商品”及“查看商品详情”功能 (1)商品类 public class Goods {public String name;public double price;public int count;public String desc;public Goods(String name, double p…

敏捷开发——第二次作业JS/服务器的部署

部署 Web 服务器 1. 安装 Apache HTTP 服务器并部署静态网页应用 ⭐⭐ 默认情况下,Apache 在 /var/www/html 目录下寻找要提供服务的文件。可以将静态网页文件放置在这个目录下 2.安装 Nginx 并部署静态页面应用 3. 实践部分 1. 2. 3. 在 /var/www/html 目录下…

用大语言模型控制交通信号灯,有效缓解拥堵!

城市交通拥堵是一个全球性的问题,在众多缓解交通拥堵的策略中,提高路口交通信号控制的效率至关重要。传统的基于规则的交通信号控制(TSC)方法,由于其静态的、基于规则的算法,无法完全适应城市交通不断变化的…

又一款代码神器,效率直接翻倍!免费的还是香啊!

前言 提到商汤科技,你可能仍然将其与“AI四小龙”、“计算机视觉领军企业”等标签联系在一起。然而,在ChatGPT与Sora赢得广泛关注后,商汤科技依托其深厚的人工智能技术基础,迅速开发出自己的大型模型及人工智能应用产品&#xff…

网络基础(一)初识

1、计算机网络背景 1.1、网络发展 1. 独立模式: 计算机之间相互独立; 2. 网络互联: 多台计算机连接在一起,完成数据共享; 3. 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起; 4. 广域网WAN: 将远隔千里的计算机都连在一起;…

Win11右键菜单定制

0.优化目标 优化成:右键菜单优化成全量菜单选项,并精简掉我不需要的菜单选项。 具体优化步骤: 1.win11菜单恢复到win10经典状态 win11右键菜单是缩水版的,需要再次点击“显示更多选项”才能找到自己想用到的选项,再…

国内ip切换是否合规?

在网络使用中,IP地址切换是一种常见的行为,可以用于实现隐私保护、访问地域限制内容等目的。然而,对于国内用户来说,IP地址切换是否合规一直是一个备受关注的话题。在中国,网络管理严格,一些IP切换行为可能…

什么是数据中心常用的ping指令?有什么作用和功能?

什么是ping指令,它的作用是什么? ping是一种计算机网络工具,用于测试网络连接是否正常,以及确定网络延迟和丢包情况。ping的运作原理是向目标主机传出一个ICMP的请求回显数据包,并等待接收回显回应数据包。程序会按时…

基于java+springboot+vue实现的自习室座位管理系统(文末源码+Lw+ppt)23-491

摘 要 时代在飞速进步,每个行业都在努力发展现在先进技术,通过这些先进的技术来提高自己的水平和优势,自习室座位管理系统当然不能排除在外。自习室座位管理系统是在实际应用和软件工程的开发原理之上,运用java语言以及SpringBo…

【排序】插入排序与选择排序详解

文章目录 📝选择排序是什么?🌠选择排序思路🌉 直接选择排序🌠选择排序优化🌠优化方法🌉排序优化后问题 🌠选择排序效率特性 🌉插入排序🌠插入排序实现 &#…

如何一键下载微信视频号的视频至本地电脑

社交媒体平台上的短视频已经成为我们获取信息和娱乐的重要来源,尤其是微信视频号。这个平台汇聚了丰富多样的内容,从生活分享到专业知识,应有尽有。然而,有时我们可能希望将这些有趣的或有用的视频保存到本地以便离线观看或分享给…

【免费】如何考取《鲸鸿动能广告初级优化师》认证(详细教程)

鲸鸿动能广告初级优化师认证考试PC网址 初级:鲸鸿动能广告初级优化师认证-华为开发者学堂 (huawei.com) 注:免费认证,里面包含免费的课程,浏览器用Edge。 文章目录 鲸鸿动能广告初级优化师认证考试网址 前言 一、备考流程 二…

PCL点云处理之最小中值平方(Lmeds法)拟合平面(二百三十四)

PCL点云处理之 最小中值平方法(Lmeds)拟合平面(二百三十四) 一、算法介绍一、拟合原理二、具体实现1.代码2.结果一、算法介绍 (本文提供详细注释,输出拟合平面参数和平面点云) Lmeds(Least Median of Squares)是一种统计学方法,用于拟合数据并减少异常值对拟合结果…

MySQL数据库 - 事务

1. 事务的概念 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中, 要删除一个人员,即需要删除人员的基本资料,又需要删除和该人员相关的信息,如信箱, 文章等等。这样&#x…

总结 | vue3项目初始化(附相应链接)

如何运行 vue 项目:vscode运行vue项目_vscode启动vue项目命令-CSDN博客 vue3项目搭建 目录管理 git管理: 目录调整: 克隆项目,绑定自己的库:[git] 如何克隆仓库,进行项目撰写,并绑定自己的…

kotlin中使用ViewBinding绑定控件

kotlin中使用ViewBinding绑定控件 什么是ViewBinding? View Binding是Android Studio 3.6推出的新特性,主要用于减少findViewById的冗余代码,但内部实现还是通过使用findViewById。通过ViewBinding,可以更轻松地编写可与视图交互…

数据库专题(基础)

前言 本专题主要记录自己最近学的数据库,有兴趣一起补习的可以一起看看,有补充和不足之处请多多指出。希望专题可以给自己还有读者带去一点点提高。 数据库基本概念 本模块有参考:数据库基本概念-CSDN博客 数据库管理系统是一个由互相关联的…

Pake一键打包,轻松构建桌面级应用!

Pake:顷刻之间,智能封装——WEB到桌面瞬间联通,让网站应用像搭积木般部署 - 精选真开源,释放新价值。 概览 Pake,作为一款新颖且极具创新性的桌面应用开发框架,凭借其独特的技术路径和高效的实现方式&…

【python】flask请求钩子,主动抛出异常与异常捕获

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

头部银行 AI 落地实践|数据应用赋能经营管理闭环

数据要素在银行各业务领域和流程中发挥着至关重要的作用,面对激烈的市场竞争和客户需求,银行越来越注重从数据管理中寻求效益和增值,深入洞察市场动态和客户需求,从而优化其产品与服务,提升运营效率和市场营销的成效。…