目录
软件测试流程:需求分析—>测试计划—>测试设计—>测试执行—>测试报告
“听书|听我想听”项目可以为用户提供听音乐与创作音乐的平台。对于该项目细化需求,提炼出相关测试点,对于这些点都需要进行全面测试。
功能需求:
用户注册、登录与退出——能成功注册与登录与退出
音频的上传、音频录制、展示音频列表——能成功上传、录制、展示
创建专辑、关联音频与展示专辑列表——能成功创建专辑,展示列表,成功绑定音频
性能需求:多个用户同时登陆时运行速度正常、内存正常、系统稳定
安全需求:用户密码安全
易用性需求:符合常见标准与规范,操作简单、方便、直观
界面需求:布局、排版美观
兼容性需求:各种浏览器都能正常访问;用户数据在后台存储时互不影响
| 测试目的 | 验证软件功能实现等是否正确,软件是否能满足用户需求 |
| 测试前提 | 系统运行正常 |
| 测试范围 | 整个项目 |
| 测试依据 | 测试用例 |
| 测试方式 | 手工+自动化测试(编写自动化脚本) |
| 测试工具 | Junit框架、selenium、LoadRunner |
| 测试环境 | Windows系统 |
| 测试功能模块
| 用户模块(注册、登录、退出) |
| 音频模块(上传、音频列表、在线录制) | |
| 专辑模块(创建专辑;专辑列表) |
针对专辑列表这一功能点设计测试用例

以专辑列表页为例
| 界面测试(访问: http://127.0.0.1:8080/studio/album/list.html 进入专辑列表页面) | 界面布局 | 登录状态下 | 展示三个模块:用户姓名、专辑列表、返回创作中心按钮
|
| 模块上下结构分布,排版合理 | |||
| 字体格式大小美观 | |||
| 图片格式大小完全相同 | |||
| 用户名展示正确 | |||
| 未登录状态下 | 弹出框提示未登录正确 | ||
| 用户名展示处显示用户未登录,请返回创作中心登录的展示 | |||
| 无专辑列表的显示 | |||
| 按钮正常 | |||
| 按钮展示 | 鼠标滑动到返回创作中心按钮处箭头指向会变为手指指向,点击按钮按钮会下移,松开会恢复到原位置 | ||
| 功能测试 | 链接跳转 | 点击绑定跳转到音频绑定界面 | |
| 点击下线专辑按钮变为已下线,同时下线按钮变为发布按钮 | |||
| 点击发布专辑状态变为已发布且发布按钮变为下线按钮 | |||
| 点击返回创作中心会返回创作中心页面 | |||
| 从上传专辑页面上传的专辑成功展示在了专辑列表页面 | |||
| 专辑上下线 | 对专辑的发布及下线信息可正常做修改 | ||
| 按钮点击 | 点击返回创作中心按钮,返回了创作中心页面,按钮可正常点击 | ||
| 兼容性测试 | 网页兼容性 | Chrome浏览器可正常访问 | |
| Firefox可正常访问 | |||
| 搜狗高速浏览器可正常访问 | |||
| edge可正常访问 | |||
| 对用户数据的兼容性 | 数据库中添加专辑列表的相关字段,不会影响其他专辑的展示 | ||
| 易用性测试 | 直观舒适 | 用户对自己的操作有感知 | |
| 实用 | 可直接进行音频绑定,专辑上下线与直接可返回创作中心 | ||
| 性能测试 | 运行速度 | 启动24h,24*3h内可正常运行 | |
| 用户访问 | 支持用户同时访问(loadRunner) | ||
单元测试就是针对最小的功能单元编写测试代码,Java 程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性,这里运用Junit框架进行测试,导入依赖后进行如下测试:
1)针对UserRepo类对用户注册的插入元素、用户登录有关的取出元素方法进行了测试
- package com.wy.tingshu.repository;
- import com.wy.tingshu.data_object.UserDO;
- import org.junit.jupiter.api.Test;
-
- public class TestUserRepo {
- UserRepo userRepo=new UserRepo();
- UserDO userDO=new UserDO();
- @Test
- public void testInsert(){
- UserDO userNow=new UserDO();
- userDO.setUsername("小心超人");
- userDO.setPassword("123");
- userRepo.insert(userDO);
- }
- @Test
- public void testSelectOneByUsername(){
- userDO.username=userDO.getUsername();
- userDO.password=userDO.getPassword();
- userDO.uid=userDO.getUid();
- System.out.println(userDO);
-
- }
- }
注册:插入一个用户;登录:将用户信息(uesername,password,uid)拿出

结果分析:由于小心超人这个用户在表中已经存在,所以只有登录后的成功展示信息,而注册则会出错。两个方法只通过了获取用户这个方法。
2)针对专辑相关操作如展示专辑列表、创建专辑进行测试
- package com.wy.tingshu.repository;
- import com.wy.tingshu.data_object.AlbumDO;
- import com.wy.tingshu.data_object.UserDO;
- import org.junit.jupiter.api.Test;
-
- public class TestAlbumRepo {
- AlbumRepo albumRepo=new AlbumRepo();
- AlbumDO albumDO=new AlbumDO();
- //插入专辑
- @Test
- public void testInsert(){
- albumRepo.insert(10,"文章标题","封面图",2);
- }
- //展示插入的专辑
- @Test
- public void testSelectListByUid(){
- System.out.println(albumRepo.selectListByUid(10));
- }
- }
结果:专辑插入与展示功能正常

1)Junit特点
a.JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法
b.JUnit可以生成全部方法的测试报告
c.单元测试中的某个方法测试失败了,不会影响其他测试方法的测试
d.在测试方法上使用@Test注解:标注该方法是一个测试方法
e.测试方法必须是public void,即公共、无返回数据
f.选中测试方法,选中 “JUnit 运行”,如果 测试良好则是绿色;如果测试失败,则是红色

2)Junit常用注解(Junit4.xxx版本)
@Test
在Junit3中,所有的测试类必须继承Junit的测试基类。在Junit4中,定义一个测试方法只需要在方法前加上@Test。
@Ignore
@Ignore修饰的方法会被忽略不执行同时不计入用例数。但要注意此标注的时候不能与其它标注一起使用,否则无效。不建议使用Ignore标注,因为容易忘记更新测试方法,造成用例遗漏等。
@BeforeClass:
在测试类里所有用例运行之前,运行一次这个标注修饰的方法(只会运行一次)。
@AfterClass:
跟@BeforeClass对应,在测试类里所有用例运行之后运行一次该标注修饰的方法,用于处理一些测试后续工作,例如清理数据,恢复现场。
@Before
每个用例运行之前都运行一次该标注修饰的方法,适用于独立的用例间,运行次数取决于用例数。
@After
每个用例运行之后都运行一次该标注修饰的方法,适用于独立的用例间,运行次数取决于用例数。
1)注册的测试(test_1register)
2)登录是正常的登陆时的情况及专辑列表页面的展示的测试(test_loginBynormalAndList)
3)登录是异常登录时的情况及专辑列表页面的显示的测试(test_loginByAbnormalAndList)
- from selenium import webdriver
- import unittest
- import os
- from selenium.webdriver.common.by import By
- from ddt import ddt,unpack,data,file_data
-
- import time #导入需要的工具包
-
- @ddt
- class User(unittest.TestCase):
- def setUp(self):
- print("----setUp-----")
- self.driver=webdriver.Chrome()
- self.url = "http://127.0.0.1:8080/studio/"
- self.driver.maximize_window()
- time.sleep(3)
-
- #注册
- @data(['胡图图','123'],['',''])
- # @unittest.skip("skipping")
- @unpack
- def test_1register(self,user,password):
- driver =self.driver
- url=self.url
- driver.get(url)
- driver.find_element(By.LINK_TEXT, '注册').click()
- time.sleep(6)
- driver.find_element(By.ID, 'username').send_keys(user)
- driver.find_element(By.ID, 'password').send_keys(password)
- time.sleep(6)
- driver.find_element(By.ID, 'submit').submit()
- time.sleep(5)
- driver.quit();
-
- #登录+展示专辑列表(成功登录时的测试)
- @data(['开心超人', '123'], ['喜羊羊', '123'])
- # @unittest.skip("skipping")
- @unpack
- def test_loginBynormalAndList(self, user, password):
- driver = self.driver
- url = self.url
- driver.get(url)
- driver.implicitly_wait(10) # 智能等待
- driver.find_element(By.LINK_TEXT, '登录').click()
- time.sleep(6)
- driver.find_element(By.ID,'username').send_keys(user)
- driver.find_element(By.ID,'password').send_keys(password)
- time.sleep(4)
- driver.find_element(By.ID,"submit").submit()
- time.sleep(5)
- driver.find_element(By.LINK_TEXT, '专辑列表').click()
- time.sleep(6)
- driver.quit();
- # 登录+展示列表(异常登录时的测试)
- @data(['开心超人', '13'], ['喜羊羊', '1234'])
- @unpack
- def test_loginByAbnormalAndList(self, user, password):
- driver = self.driver
- url = self.url
- driver.get(url)
- driver.implicitly_wait(10) # 智能等待
- driver.find_element(By.LINK_TEXT, '登录').click()
- time.sleep(6)
- driver.find_element(By.ID,'username').send_keys(user)
- driver.find_element(By.ID,'password').send_keys(password)
- time.sleep(4)
- driver.find_element(By.ID,"submit").submit()
- time.sleep(5)
- url = self.url
- driver.get(url)
- time.sleep(3)
- driver.find_element(By.LINK_TEXT, '专辑列表').click()
- time.sleep(6)
- alert=driver.switch_to.alert#定位弹出框操作句柄
- time.sleep(3)
- alert.accept()#关闭弹出框
- time.sleep(5)
- driver.quit();
-
-
- def tearDown(self):
- print("----tearDown----")
- self.driver.quit()
- if __name__ =="__main__":
- unittest.main()
见手工测试表格
- import HTMLTestRunner
- import os
- import sys
- import time
- import unittest
- def createsuite():
- discovers=unittest.defaultTestLoader.discover("../venv",pattern="mycode.py",top_level_dir=None)#一个类就是一个测试套
- print(discovers)
- return discovers
-
- if __name__=="__main__":
- #1.创建一个文件夹
- curpath=sys.path[0]#当前工具类的一个集合/路径集合数组,0指的是当前文件所在路径
- print(sys.path)
- print(sys.path[0])
- #2.当前路径下resultReport文件夹不存在时,创建
- if not os.path.exists(curpath+'/resultreport'):
- os.makedirs(curpath+'/resultreport')
- #解决重复命名问题
- now =time.strftime("%Y-%m-%d %H %M %S",time.localtime(time.time()))
- print(time.time())
- print(time.localtime(time.time()))
- #3.准备HTML报告输出的文件
- #文件名是路径+文件名称+时间
- filename=curpath+'/resultreport'+now+'resultreport.html'
- #打开HTML文件,wb以写的方式输入运行的那个结果
- with open(filename,'wb') as fp:
- #括号中的参数是HTML报告中的参数
- runner=HTMLTestRunner.HTMLTestRunner(stream=fp,title=u"测试报告",description=u"用例执行情况",verbosity=2)#verbosity:结果的详细程度
- suite=createsuite()
- runner.run(suite)
-
