自动化测试 - 黑马头条测试项目
黑马头条测试项目
1. 自动化测试流程
1. 自动化测试流程
- 需求分析
- 挑选适合做自动化测试的功能
- 设计测试用例
- 搭建自动化测试环境
- web自动化测试环境(4个)
- python开发者工具(pycharm, python解释器)
- 浏览器
- 浏览器驱动
- selenium
- app自动化测试环境(5个)
- 手机或模拟器
- 安卓sdk
- python开发工具
- appium服务器
- appium服务客户端
- web自动化测试环境(4个)
- 设计自动化测试项目架构
- 编写代码
- 执行测试用例
- 生成测试报告并分析结果
2. 黑马头条项目简介
1. 项目背景
作为一个IT教育机构,拥有自己开发且实际运营的产品,将开发和运营的技术作为授课的内容,对于学员而言学到的都是一手的真实案例和实际经验,知识内容也可以细化深入。 而且一个产品就可以涵盖公司多个学科的技术,衍生的课程价值辐射多个学科。这可以作为公司的一个核心竞争力。
2. 产品定位
一款汇集科技资讯、技术文章和问答交流的用户移动终端产品。 用户通过该产品,可以获取最新的科技资讯,发表或学习技术文章,讨论交流技术问题。
3. 项目目标
- 研发并上线运营头条产品
- 从实际的产品技术中孵化产品经理、Python 人工智能、Python 数据分析、Python Web、测试、运维等课程案例
- 构建公司自己的数据仓库和算法模型
3. 产品功能架构
自媒体:又称“个人媒体”,是指私人化、平民化、自主化的传播者, 以现代化、电子化的手段,向不特定的大多数或者特定的单个人传递信息的新媒体的总称。 自媒体平台包括:博客、微博、微信、抖音、百度贴吧、论坛/BBS等网络社区。
产品主要分为三个前端子产品:
- 用户端
APP,用户可以查看资讯、文章内容,进行问答讨论交流 - 自媒体运营平台
PC网站,自媒体用户可以管理文章、评论,查看分析粉丝数据 - 系统后台
PC网站,内部运营管理系统
产品后端系统功能可分为以下几个部分:
- 推荐系统部分
负责为用户个性化推荐资讯和文章 - 人工智能部分
机器自动审核文章、文章画像提取、机器学习推荐算法等 - 日志系统部分
收集保存用户行为数据和系统运行状态数据 - 爬虫部分
爬取网站资讯文章数据,作为产品启动的初期数据来源
4. 产品技术架构
5. 负载均衡
负载均衡器: 负载均衡(Load Balance)可以将工作任务分摊到多个处理单元, 从而提高并发处理能力
负载均衡器建立在现有网络结构上, 使用它可以实现网络设备的带宽, 增加吞吐量, 加强网络数据处理能力, 提高网络的灵活性和可用性
负载均衡器在工作当中, 要么使用nginx(软件负载均衡), 要么使用F5(硬件负载均衡), 如果使用的是阿里云或者是腾讯云, SLB负载均衡, nginx既可以做负载均衡, 也可以做web前端的中间件
6. 消息队列
消息队列(Message Queue, MQ): 是在消息传输过程中保存消息的容器
消息队列中间件是分布式系统中重要的组件, 主要解决应用解耦, 异步消息, 流量削峰等问题, 实现高性能, 高可用, 可伸缩和最终一致性架构
目前使用较多的消息队列有: Kafka, ActiveMQ, RabbitMQ, ZeroMQ, MetaMQ, RocketMQ
应用场景
- 异步处理
将业务逻辑处理由串行方式变成并行方式(好友推荐, 新闻推荐) - 应用解耦
订单系统 --> 库存系统
发送短信验证码 - 流量削峰
秒杀, 抢购活动(用户访问量过大, 导致流量暴增, 应用挂掉) - 日志处理
将消息队列用早日志处理中, 解决大量日志传输的问题
7. 用例设计
1. 编写自动化测试用例的原则
- 自动化用例一般只实现核心业务流程或者重复执行率较高的功能
- 自动化测试用例的选择一般以"正向"逻辑的验证为主
- 不是所有的手工用例都可以使用自动化测试来执行
- 尽量减少多个用例脚本之间的依赖
- 自动化测试用例执行完毕后, 一般需要回到原点
2. 编写测试用例
1. 自媒体
2. 后台管理系统
3. APP
8. 自动化框架结构设计
1. 初始化项目
1. 新建项目
项目名称: uiAutoTestHmtt
2. 创建目录结构
- uiAutoTestHmtt #项目名称
- base #封装PO基类
- page #封装PO页面对象
- script #定义测试用例脚本
- data #存放测试数据
- report #存放生成的测试报告
- log #存放测试文件
- screenshot #存放截图
- config.py #定义项目配置信息
- utils.py #定义工具类
- pytest.ini #pytest配置文件
- conftest #pytest.ini运行配置
3. 安装依赖包
- selenium包
- Appium-Python-Client包
- pytest包
- pytest-ording包
- allure-pytest包
2. 初始化代码
1. 封装工具类
- 封装PO类, 定义BasePage和BaseHandle
- pytest.ini
[pytest]
addopts = -s -v --html=report/report.html --reruns 3
testpaths = ./uiAutoTestHmtt/script
python_files = test_*.py
python_classes = Test*
python_functions = test_*
- utils.py
from selenium import webdriver
from appium import webdriver as appdriverclass UtilsDriver:_mp_driver = None #表示的是自媒体平台的驱动_mis_driver = None #表示的是后台管理驱动_app_driver =None # 表示的是app的驱动# 定义获取自媒体平台的浏览器驱动@classmethoddef get_mp_driver(cls):if cls._mp_driver is None:cls._mp_driver = webdriver.Chorm()cls._mp_driver.get("http://ttmp.research.itcast.cn/")cls._mp_driver.maximize_window()return cls._mp_driver# 定义退出自媒体平台浏览器驱动@classmethoddef quit_mp_driver(cls):if cls._mp_driver is not None:cls.get_mp_qdriver().quit()cls._mp_driver = None# 定义获取后台管理的驱动@classmethoddef get_mis_driver(cls):if cls._mis_driver is None:cls._mis_driver = webdriver.Chrom()cls._mis_driver.maximize_window()cls._mis_driver.get("http://ttmis.research.itcast.cn/")return cls._mis_driver# 定义退出后台管理系统操作方法@classmethoddef quit_mis_driver(cls):if cls._mis_driver is not None:cls.get_mis_driver().quit()cls._mis_driver = None# 定义获取app驱动@classmethoddef get_app_driver(cls):if cls._app_driver is None:des_cap = {"platformName": "android","platformVersion": "5.1.1","deviceName": "emulator-5554","appPackage": "com.itcast.toutiaoApp","appActivity": ".MainActivity","noReset": True, #用来记住app的session"resetKeyboard": True, #重置设备输入键盘"unicodeKeyboard": True # 采用unicode编码输入}cls._app_driver = appdriver.Romate("http://127.0.0.1:4723/wd/hub", des_cap)return cls._app_driver# 退出app浏览器驱动@classmethoddef quit_app_driver(cls):if cls._app_driver is not None:cls.get_app_driver().quit()cls._app_driver = None
基类的封装
- 媒体平台的封装
base包 -> 创建mp包 -> 在mp包下创建base.py文件
from selenium.webdriver.support.wait import WebDriverWaitfrom utils import UtilsDriver# 定义自媒体平台的基类# 对象库层基类的封装class BasePage:def __init__(self):self.driver = UtilsDriver.get_mp_driver() # 获取自媒体浏览器驱动def get_element(self, location):wait = WebDriverWait(self.driver, 10, 1)element = wait.until(lambda x: x.find_element(*location))return element# 操作层基类的封装class BaseHandle:def input_text(self, element, text):element.clear()element.send_keys(text)
- 后台管理基类封装
base包 -> 创建mis包 -> 在mis包下创建base.py文件
from selenium import webdriverfrom utils import UtilsDriver# 定义后台管理的基类# 页面对象层封装class BasePage:def __init__(self):self.driver = UtilsDriver.get_mis_driver() # 获取后台管理驱动def get_element(self, location)wait = WebDriverWait(self.driver, 10, 1)element = wait.until(lambda x: x.find_element(*location))return element# 操作层的封装class BaseHandle:def input_text(self, element, text):element.clear()element.send_keys(text)
- app基类封装
base包 -> 创建app包 -> 在app包下创建base.py文件
from selenium import webdriverfrom utils import UtilsDriver# 定义app平台的基类# 对象库层基类封装class BasePage:def __init__(self):self.driver = UtilsDriver.get_app_driver() # 获取app浏览器驱动def get_element(self, location):wait = WebDriverWait(self.driver, 10, 1)element = wait.until(lambda x: x.find_element(*location))return element# 操作层基类封装class BaseHandle:def input_text(self, element, text):element.clear()element.send_keys(text)
自媒体平台的封装
自媒体登录页面的封装
page包 -> 新建mp包 -> 创建登录界面login_page.py
from base.mp.base import BasePage, BaseHandlefrom selenium.webdriver.common.by import By# 定义对象库层
class LoginPage(BasePage):def __init__(self):super().__init__()# 手机号码输入框self.mobile = By.XPATH, "//*[@placeholder='请输入手机号']"# 验证码输入框self.code = By.XPATH, "//*[@placeholder='验证码']"# 登录按钮self.login_btn = By.CSS_SELECTOR, ".el-button--primary"# 定位手机号码输入框def find_mobile(self):return self.get_element(self.mobile)# 定位验证码输入框def find_code(self):return self.get_element(self.code)# 定位登录按钮def find_login_btn(self):return self.get_element(self.login_btn)# 定义操作层
class LoginHandle(BaseHandle):
def __init__(self):self.login_page = LoginPage()# 输入手机号码def input_mobile(self, mobile):self.input_text(self.login_page.find_mobile(), mobile)# 输入验证码def input_code(self, code):self.input_text(self.login_page.find_code(), code)# 点击登录按钮def click_login_btn(self):self.login_page.find_login_btn().click()# 定义业务层
class LoginProxy:def __init__(self):self.login_handle = LoginHandle()def login(self, mobile, code):self.login_page.input_mobile(mobile) # 输入手机号码self.login_page.input_code(code) # 输入验证码self.login_page.click_login_btn() # 点击登录按钮
自媒体平台首页封装
page包 -> 新建mp包 -> 创建登录界面home_page.py
from selenium.webdriver.common.by import Byfrom base.mp.base import BasePage, BaseHandle# 定义对象层
class HomePage(BasePage):def __init__(self):super().__init__()# 用户名显示元素self.username = By.CSS_SELECTOR, ".user-name"# 内容管理菜单self.content_manage = By.XPATH, "//*[text()='内容管理']"# 发布文章self.public_btn = By.XPATH, "//*[@class='sidebar-el-menu el-menu']/div[2]/li/ul/li[1]"# 定位用户名显示元素def find_username(self):return self.get_element(self.username)# 定位内容管理菜单def find_content_manage(self):return self.get_element(self.content_manage)# 定位发布文章菜单def find_publish(self):return self.get_element(self.publish_btn)#定义操作层
class HomeHandle(BaseHandle):def __init__(self):self.home_page = HomePage()# 获取用户名信息def get_username(self):return self.home_page.find_username().text# 点击内容管理菜单def click_content_manage(self):self.home_page.find_content_manage().click()# 点击发布文章def click_publish_btn(self):self.home_page.find_publish().click()# 定义业务层
class HomeProxy:def __init__(self):self.home_handle = HomeHandle()# 获取用户名信息def get_username_msg(self):return self.home_handle.get_username()# 跳转到发布文章页面def go_publish_page(self):self.home_handle.click_content_manage()self.home_handle.click_publish_btn()
自媒体平台发布文章页面封装
page包 -> 新建mp包 -> 创建登录界面publish_page.py
from base.mp.base import BasePage, BaseHandlefrom selenium.webdriver.common.by import By# 定义对象库层
class PublicPage(BasePage):def __init__(self):super().__init__()#文章名称输入框self.title = By.XPATH, "//*[@placeholder='文章名称']"# iframe元素对象self.iframe_ele = By.ID, "publishTinymce_ifr"# 文章内容输入框self.content = By.CSS_SELECTOR, ".mce-content-body"# 封面选择self.cover = By.XPATH, "//*[@role=radiogroup]/label[4]/span[2]"# 频道选择self.channel = By.XPATH, "//*[@placeholder='请选择']"# 发表按钮self.publish_btn = By.CSS_SELECTOR, "[class='el-button filter-item el-button--primary']"# 寻找文章标题def find_title(self):return self.get_element(self.title)# 找到切换的iframedef find_iframe_ele(self):return self.get_element(self.iframe_ele)# 找到文章内容输入框def find_content(self):return self.get_element(self.content)# 找到封面选择输入框def find_cover(self):return self.get_element(self.cover)# 定位频道选择输入框def find_channel(self):return self.get_element(self.channel)# 定位发表按钮def find_publish_btn(self):return self.get_element(self.publish_btn)# 操作层
class PublishHandle(BaseHandle):def __init__(self):self.publish_page = PublishPage()self.driver = UtilsDriver.get_mp_driver()# 输入文章标题def input_title(self, title)self.input_text(self.publish_page.find_title(), title)# 输入文章内容def input_content(self)# 切换到iframe中self.driver.switch_to.frame(self.publish_page.find_iframe())# 输入文章内容self.input_text(self.publish_page.find_input_content(), content)# 切回默认首页self.driver.switch_to.default_content()# 选择封面def choice_cover(self):self.publish_page.find_cover().click()#选择频道def choice_channel(self):choice_channel(self.driver, self.publish_page.find_channel_choice(), channel)#点击发布按钮def click_publish_btn(self):self.publish_page.find_publish_btn().click()# 业务层封装
class PublishProxy:def __init__(self):self.publish_handle = PublishHandle()# 发布文章def publish_article(self, title, content, channel):# 输入文章标题self.publish_handle.input_title(title)self.publish_handle.input_content(content)self.publish_handle.choice_cover()self.publish_handle.choice_channel(channel)self.publish_handle.click_publish_btn()
在utils模块中封装选择频道的方法
......
def choice_channel(driver, element, channel)
"""
param driver: 浏览器驱动对象
param element: 选择元素
param channel: 要选择的文本内容
"""
element.click()
time.sleep(1)
xpath = "//*[@class='el-select-dropdown__wrap el-scrollbar__wrap']//*[text()='{0}']".format(channel)
driver.find_element(By.XPATH, xpath).click()
在utils中封装一个方法, 判断元素是否存在
......
# 封装一个方法判断元素是否存在
def is_exis(driver, text):"""param driver: 浏览器驱动对象param text: 定位元素的文本内容"""xpath = "//*[contains(text(), '{0}')]".format(text)try:time.sleep(2)return driver.find_element(By.XPATH, xpath)expect Expection as e:return False
自媒体测试用例的编写
scripts模块 -> 创建mp模块 -> 创建test_publish_article.py文件
from page.mp.login_page import LoginProxy
from page.mp.home_page import HomeProxy
from page.mp.publish_page import PublishProxyclass TestPublishArticle:# 定义类级别的fixture初始化方法def setup_class(self):self.login_proxy = LoginProxy()self.home_proxy = HomeProxy()self.publish_proxy = PublishProxy()# 定义类级别的fixture销毁方法def teardowm_class(self):UtilsDriver.quit_mp_driver()# 定义登录测试用例def test_login(self):self.login_proxy.login("18815687257", "246810")username = self.home_proxy.get_username_msg()assert "test123" == username# 定义文章测试用例def test_publish_article(self):self.home_proxy.go_publish_page()self.publish_proxy.publish_article("发布文章_0321_09", "发布文章_0321_09发布文章_0321_09", "数据库")assert is_exist(UtilsDriver.get_mp_driver(), "新增文章成功")
后台管理系统页面的封装
后台管理系统登录页面的封装
page包 -> 新建mis包 -> 创建登录界面login_page.py
from selenium.webdriver.commom.by import By
'''页面对象层'''
class LoginPage(BasePage):def __init__(self):super().__init__()self.username = By.Name, "username"self.password = By.Name, "password"self.login_btn = By.ID, "inp1"# 定位用户名输入框def find_username(self):return self.get_element(self.username)# 定位密码框def find_password(self):return self.get_element(self.password)# 定位登录按钮def find_login_btn(self):return self,get_element(self.login_btn)"""操作层"""
class LoginHandle(BaseHandle):def __init__(self):self.login_page = LoginPage()# 输入用户名def input_usernane(self, username):self.input_text(self.login_page.find_username(), username)# 输入密码def input_password(self, password):self.input_text(self.login_page.find_password(), password)# 点击登录def _click_login_btn(self):# 定义JSjs = "document.getElementById('inp1').removeAttribute('disabled')"# 通过execute_script方法执行JSself.login_page.driver.execute_script(js)# 点击登录按钮self.login_page.find_login_btn().click()# 定义业务层
class LoginProxy:def __init__(self):self.login_handle = LoginHandle()# 登录业务操作def login(self, username, password):self.login_handle.input_username(username)self.login_handle.input_password(password)self.login_handle.click_login_btn()
后台登录系统主页的封装
page包 -> mis包 -> 创建登录界面home_page.py
# 页面对象层
class HomePage(BasePage):def __init__(self):super().__init__()# 用户信息self.user_info = By.CSS_SELECTOR, ".user_info.span"# 信息管理seld.content_manage = By.XPATH, "//*[@class='side_bar']/ul/li[3]/a"# 内容审核self.content_audit = By.XPATH, "//*[@class='current3']/li[3]/a"# 定位用户信息def find_user_info(self):return self.get_element(self.user_info)# 定位信息管理菜单def find_content_manage(self):return self.get_elememt(self.content_manage)# 定位内容审核状态def find_context_audit(self):return self.get_element(self.content_audit)# 定义操作层
class HomeHandle(BaseHnadle):def __init__(self):self
自动化测试 - 黑马头条测试项目相关推荐
- 黑马头条推荐项目知识点总结(一)
实际生产环境中,我们要处理的数据来自可能各个地方,业务数据库,爬虫数据库,日志文件,api网关买入数据等. 本次黑马头条推荐项目中,业务数据存储在mysql中,用户行为数据存储在日志中,因此采用两种技 ...
- 2019黑马python面试资料_2019最新Python黑马头条推荐系统项目
『课程目录』:├─黑马头条推荐第一天) L) P$ Q$ }7 U│ ├─01_视频 │ │ 01_黑马头条推荐架构与业务流 │ │ 02_开发环境介绍( k# }! [2 n8 S$ }│ │ 03 ...
- 黑马python2019_2019最新Python黑马头条推荐系统项目
『课程目录』:├─黑马头条推荐第一天) L) P$ Q$ }7 U│ ├─01_视频 │ │ 01_黑马头条推荐架构与业务流 │ │ 02_开发环境介绍( k# }! [2 ...
- python视频教程推荐it教程网_2019年最新Python黑马头条推荐系统项目开发视频教程完整版...
课程定位 * 课程是机器学习(包含推荐算法)算法原理在推荐系统的实践 * 深入推荐系统的业务流场景.工具使用 * 作为人工智能的数据挖掘(推荐系统)方向应用项目 ## 课程目标 * 熟练掌握推荐系统的 ...
- 黑马头条移动项目(一):项目介绍、项目技术点介绍、项目包介绍
1. 项目介绍 黑马头条移动端是一个IT资讯移动web应用,有着和今日头条类似的资讯浏览体验. 主要功能:资讯列表.标签页切换,文章举报,频道管理.文章详情.关注功能.点赞功能.评论功能.搜索功能.登 ...
- 黑马头条移动项目(十):登录页面的布局
目标 能实现登录页面的布局 1. 登录页面的布局 1.1 创建组件并配置路由,访问登录页面 src/views/Login/index.vue - 作为登录页面 - 先随意弄写标签显示 <tem ...
- 软件测试项目实战32讲,软件测试入门-黑马头条项目实战
课程简介 本课程以黑马头条实战项目为例,将项目的整个测试流程做了详细的介绍,并带着大家一起进行产品需求评审,项目测试计划编写,测试需求分析,以及测试用例的设计编写和执行操作,通过完成实际的功能业务测试 ...
- Python黑马头条推荐系统第一天 架构介绍和离线计算更新Item画像
Python黑马头条推荐系统项目课程定位.目标 定位 课程是机器学习(包含推荐算法)算法原理在推荐系统的实践 深入推荐系统的业务流场景.工具使用 作为人工智能的数据挖掘(推荐系统)方向应用项目 目标 ...
- 前端基础第五天项目 社交媒体黑马头条项目-文章模块和评论
七.文章详情 创建组件并配置路由 1.创建 views/article/index.vue 组件 <template><div class="article-contain ...
最新文章
- 2019年十大数据与分析技术趋势
- 【Linux+vscode】配置好秘钥之后还是不能ssh连接(离线配置)
- oracle 带有变量的语句_Oracle 动态SQL语句(2)之含变量的WHERE语句与日期变量
- How to resolve ATC error message Package Violation (Error) - Missing Use Access (USEM)
- Navigator 对象,能够清楚地知道浏览器的相关信息
- 1.0jpa 2.0_JPA 2.1实体图–第1部分:命名实体图
- 第五十一期:互联网不如国企,去BAT的程序员都是diao丝?
- 自定义View(四) ViewGroup 动态添加变长Tag标签 支持自动换行
- 凸函数与简森不等式(Jensen's inequality)
- 通过实例学习编写需求文档 【转】
- OSPF与EIGRP的比较
- 锦锐单片机开发工具_飞思卡尔单片机PE开发工具硬件及软件
- 色彩转换系列之RGB格式与YUV格式互转原理及实现
- oracle 函数索引
- R语言和医学统计学(4):秩和检验
- NYOJ - 小柯的编译器
- 【JavaSE】自定义异常
- STM32 实数FFT 极速配置
- 基于Python的二维有限元声波方程正演计算
- java 初级、中级、高级工程师
热门文章
- phpstorm使用教程
- 解密宜人贷:科技驱动金融创新
- 关于日本川崎重工中标高速铁路的事
- Mybatis报错org.apache.ibatis.binding.BindingException: Type interface com.trf.dao.UserDao is not known
- ssh 连接报错:Unable to negotiate with 192.168.xx.xx port 22: no matching key exchange method found.
- 面向 C++ 的测试驱动开发
- 2021年秋招面经分享·乐鑫【数字IC设计工程师】
- 华为交换机M-LAG配置
- 计算机图形学课程总结
- win10_940MX python3.6深度学习gpu环境搭建入门必看!anaconda3+cuda9.0+cudnn7.0.5+tensorflow1.7.0+keras2.1.6+openCV