接下来,我将开始散文式地记录我作为一位从业3年多的软件测试人员的软测经验。这是我在繁忙的日常工作的中跋涉出来又又投入的另一工作(bushi)另一兴趣中去。
我将简单(偏流水线向)从业务/技术/项管三个方面简单汇总一下我的日常工作。后期可再针对使用到的具体技术的详解再开篇。
测试用例,好像是每个讲软测经验的文章的基本输出。各种测试用例的设计及白盒黑盒测试方法重复出现在收集者前面。so,不走寻常路的我,决定从另外的角度去分享测试用例。日常工作中,项目上线出现的大大小小的问题都会被我收入囊中,记录在册,可以说我的项目复盘手册都快被我盘包浆了。aha 以我做过的一个电子签约项目平台为例子,这是一个中型项目,前期后期紧赶慢赶,也算把项目成功交付。后我们组织做了一次复盘会,基本复盘总结如下
利用正交法+场景法,列出所有参数(如参与方、签署文档等)及其水平参数(如参与方有单参与方和多参与方),将其有序地组合成一个个场景,这样可以很好地覆盖项目的主要功能流程,以保障主要业务流程尽可能不漏测。
如此总总,就不一一 枚举。总而言之,业务流程上,正交法+场景法yyds;其他普通功能点,上面的涉及到的,直接cv,复用率极高。
jmeter-反电诈项目
这个我做过的一个非常有意义的项目,和腾讯合作的,主要为用户拦截并提示所有可能涉及到的诈骗类型,并以裂变的形式扩展用户,这个项目前期后端先完成,并出了完善的API文档,数据库设计说明,这不则正是为接口自动化提供了良好的前期条件么。于是我组织组内测试人员经过5天时间设计并完成了关于该项目的jmeter接口自动化脚本的编写,并将其简单转化成性能、稳定测试的脚本。
下面截图是对用户变量的描述,放于测试计划下,作用于所有线程组(这些变量一旦定下,无需再修改,最后执行的tearDown线程组会直接从测试数据库删除这些变量以达到无限重复使用,达成自动化的实现)
一个线程,原则上由一个功能点的1个或多个接口组成,需从正向和反向测试。
主要接口的性能脚本编写
这边就浅浅说一下性能测试较值得分享的技能,大数据量级别的接口数据关联如何实现。
xx项目的主要业务接口需要进行性能测试,而该接口实现的前提是登陆接口请求后获得的token作为其请求头。单用户的接口可以直接通过关联的方式实现该功能。而性能接口测试的目的就是获取目标接口的某数量级别请求后的具体数据(tps,qps等),如利用多接口关联则会破坏数据的真实性。
实际工作中,我使用了BeanShell 后置处理程序处理了该问题,使得性能测试数据更独立,更真实、可用度更高。具体实现方式如下:
利用BeanShell把响应结果写入本地
添加配置元件:CSV 数据文件设置,从CSV文件读入,后续直接引用TOKEN
这是算我第一次比较全面,系统的建立一个UI自动化的测试框架,真真从0到1的突破。
首先就是从框架的选取,挑选合适做自动化测试的功能,设计对应的测试用例。我选择的pytest框架,详细框架架构如图
Jenkins的作用不用我多说大家都知道,部署环境、定时跑任务。那在测试工作的环节上就免不了跟测试自动化挂钩上。
下面我将从两方面介绍Jenkins在我测试工作中的举足轻重的作用。
上章节我们介绍到jmeter自动化脚本的编写,写完呢,每次测试的时候都大费周章的打开jmeter,然后一线程一线程的执行,然后再去根据结果树,一个一个的查看结果、分析。如果领导需要一份测试报告,还要费尽脑汁的重立框架、组织语言去总结输出文档。NoNoNo 这绝不是一个成熟的测试工程师的工作样本。以始为终,为降本增效,我们就需要利用到Jenkins了。
源码管理
构建触发器
构建
构建后操作
bug统计的Jenkins项目配置截图
测试左移,这个概念在日常测试工作中常有听说,但是左移的实践甚少。这也将是以后高级测试发展的方向,如代码路径测试、针对代码的建议,如正则表达式匹配的建议等
在我后半段的测试工作经验中也涉及较多。如专门设计的生产问题反馈的处理流程、协作安排、处理人员的调度、跟进修复的进度、及时复测以便更版生产。
某天老板叫我到办公室,严肃地问了我一个问题:你觉得目前的开发人中,谁的水平最高,工作效率最快。好家伙,这不能妥妥得罪人的问题么,这开发老师我们平时可是放在手心上哄的呀。这锅我不能背,那就让数据说话吧。于是乎,我想到禅道,禅道可是妥妥记录开发在测试员的整个‘成长历史’:模块开发时长、开发产生bug数、bug修复时长、bug激活次数、bug的遗留个数等等。我反手就打开我的pycharm,整了以下关于禅道的sql语句,统计出我要的数据,通过python的整理,以htlml的格式将数据每日定时发送至钉钉群,方便老板以及各部门领导更好的每日观察各位开发的工作情况。
def bug_total(self, cursor, now,begin_day,total_day):
"""
最近总的BUG情况统计统计
:param: day 根据输入天数
:return:
"""
# 新增bug数
new_near_bug_sql = """SELECT COUNT(*) as new_near_bug from zt_bug where openedDate between "%s" and "%s" and deleted='0';""" % (begin_day, now)
cursor.execute(new_near_bug_sql)
new_near_bug = cursor.fetchone()
# print("新增bug数")
# print(new_near_bug)
# 已解决bug数
close_bug_sql = """SELECT COUNT(*) as close_bug from zt_bug where status = "closed" and openedDate between "%s" and "%s" and deleted='0';""" % (begin_day, now)#"%s"表示这里将被替换成一个新的字符串,依次为recent_sevenday, now
cursor.execute(close_bug_sql)
close_bug = cursor.fetchone()
# print("已解决bug数")
# print(close_bug)
# 未解决bug数
open_bug_sql = """SELECT COUNT(*) as open_bug from zt_bug where status = "active" and openedDate between "%s" and "%s" and deleted='0';""" % (begin_day, now)
cursor.execute(open_bug_sql)
open_bug = cursor.fetchone()
# print("没解决bug数",)
# print(open_bug)
# 已解决待验证bug数
close_unbug_sql = """SELECT COUNT(*) as close_unbug from zt_bug where status = "resolved" and openedDate between "%s" and "%s" and deleted='0';""" % (begin_day, now)
cursor.execute(close_unbug_sql)
close_unbug = cursor.fetchone()
# print("已解决待验证bug数", )
# print(close_unbug)
#研发人员发生bug数排行。
dev_bug_sql = """SELECT COUNT(*) num,realname FROM zt_bug b INNER JOIN zt_user u ON u.account = b.resolvedBy
WHERE DATE_FORMAT(b.openedDate, '%%Y-%%m-%%d') between '%s' and '%s'
AND u.deleted='0' AND u.role='dev'
GROUP BY b.resolvedBy ORDER BY num DESC;""" % (total_day, now)
cursor.execute(dev_bug_sql)
dev_bug = cursor.fetchall()
print("研发人员发生bug数降序排行", )
# print(dev_bug)
add_str_dev_bug = '' # 空字符串
#让降序排行一行一人
for _tuple in dev_bug:
a = ' \n \n {0}'.format(
_tuple)
add_str_dev_bug += str(a)
#研发人员发生bug激活数排行。
activation_bug_sql = """SELECT SUM(激活次数) 激活次数,中文姓名 FROM (SELECT b.id,COUNT(*) 激活次数,u.realname 中文姓名 FROM
zt_bug b INNER JOIN zt_action a ON a.objectID = b.id INNER JOIN zt_user u ON u.account = b.resolvedBy
WHERE DATE_FORMAT(b.openedDate, '%%Y-%%m-%%d') between "%s" and "%s" AND a.objectType = 'bug' AND a.action = 'activated'
AND u.deleted='0' and u.role='dev'
GROUP BY b.id ORDER BY 激活次数 DESC) tem GROUP BY tem.中文姓名 ORDER BY 激活次数 DESC;""" % (total_day, now)
cursor.execute(activation_bug_sql)
activation_bug = cursor.fetchall()
print("研发人员BUG被激活次数(非一次性修复)", )
print(activation_bug)
add_str_activation_bug = '' # 空字符串
#让降序排行一行一人
for _tuple in activation_bug:
a = ' \n \n {0}'.format(
_tuple)
#(Decimal('19')中的(Decimal('')去掉
a = re.sub('[(Decimal('')]', '', a)
# print(a)
add_str_activation_bug += str(a)
# print("拆开元组,研发人员BUG被激活次数(非一次性修复)", )
# print(add_str_activation_bug)
# 提BUG、指派、转派【已解决待验证】、改BUG,=====================\n\n研发人员BUG被激活次数(非一次性修复):{5}\n\n
statistics_bug = "本年度新增bug总情况({6}~{7}) \n\n 新增BUG数:{0} \n\n 未关闭BUG数:{1} \n\n 已关闭BUG数:{2} \n\n 已解决待验证BUG数:{3}\n\n =====================\n\n研发人员今年(2023)BUG数倒序:\n\n{4}\n\n =====================\n\n研发人员今年BUG被激活次数(非一次性修复):\n\n{5}\n\n".format(
new_near_bug[0], open_bug[0], close_bug[0], close_unbug[0], add_str_dev_bug, add_str_activation_bug, total_day, now)
# print("bug的统计汇总:"+statistics_bug)
return statistics_bug
import datetime
from dingtalkchatbot.chatbot import DingtalkChatbot, FeedLink
class ding_talk():
def send_bug(self,url, data_file,sign_mark):#设置发送的信息样式
'''
:param url: 钉钉机器人的webhook
:param data_file: 查看详情中的markdown信息
:param sign_mark: 用户而可以自定义字段为本周、还是本月的禅道BUG情况统计
:return:
'''
xiaoding = DingtalkChatbot(url)
# Markdown消息@所有人
now = datetime.datetime.now().strftime("%Y%m%d")
# print("当前时间:"+str(now))
# 含html
xiaoding.send_markdown(title='BUG统计%s' % (now),
text='**禅道BUG情况统计**\n\n 各位同事,以下是禅道BUG情况统计。统计结果供各组组长参考,烦请做好督促,尽快处理bug!\n\n=====================\n\n {0} \n\n[查看历史遗留bug详情](http://192.168.100.135:9080/test/bugdetail.html) \n'.format(
data_file,now), is_at_all=False)
data_file, now), is_at_all=False)
def bug_html2(self, lis, html_file):
"""
对查询bug明细转html文件
:param lis
:param html_file
"""
"""
对查询bug明细转html文件
:param lis
:param html_file
"""
conten_title = []
for key in ( "项目名称","开始", "结束","姓名", "bug标题", "bug_id"):
conten_title.append(key)
a = "</th><th>".join(conten_title)
con_title = "<tr><th>" + a + "</th></tr>"
conten_val = ""
con = ""
# lis_arr = lis.fetchall()
for i in range(0, len(lis)):
for index, v in enumerate(lis[i]):
if index == 0:
# 20231114修复字符串拼接
conten_val = "<tr><td>" + str(lis[i][index]) + "</td><td>"
# conten_val = "<tr><td>" + lis[i][index] + "</td><td>"
con = con + conten_val
continue
con = con + str(lis[i][index]) + "</td><td>"
con = con[0:-2] + "r>"
con = con + "\n"
head = """<meta charset="utf-8">
<style type="text/css">
table.tftable {font-size:12px;color:#333333;width:100%;border-width: 1px;border-color: #9dcc7a;border-collapse: collapse;}
table.tftable th {font-size:12px;background-color:#abd28e;border-width: 1px;padding: 8px;border-style: solid;border-color: #9dcc7a;text-align:left;}
table.tftable tr {background-color:#ffffff;}
table.tftable td {font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #9dcc7a;}
</style>\n<table id="tfhover" class="tftable" border="1">\n"""
last = "</table>"
htm = head + con_title + con + last
with open(html_file, "w+", encoding="utf-8") as f:
f.write(htm)
这个其实也涉及到我们上面提到的测试右移
组织每日站立会议,主要内容就是:跟进1.0项目的总体进度,及时反馈项目的各种可能发生的风险:如延迟,功能点偏移;汇总2.0+的项目生产问题、新需求、优化等。关于晨会每日的汇总表格,简单而优雅,不失重点,涉及有具体问题、具体人员、具体处理点、具体完成时间都要详细绘出。及时做好与需求提出者(产品or运营)的沟通,反馈研发的整个流程的问题处理情况。
汇总、跟进项目(新旧项目,需求、优化、bug)
质量检查-质量保证
这一点其实主要是本人对测试行业的。。算是浅薄认知吧。以前讲测试,我们都理所当然地想到这是讲质量检查。基操就是:发现问题,、反馈问题、待处理问题后复测问题。这个流程都是相对被动的。被产品告知需求,被开发告知提测,待开发修复问题,待运维上线不同环境,再次冒烟。
是否,我们能从被动,慢慢转向主动,从质检,慢慢转向真正意义上的质保。毕竟,成熟的测试是要能提得了需求,开发得了代码(bushi)成熟的测试应能对产品的质量做出保证,竭尽全力在测试的过程中尽多地找出bug,尽全力提高DDP(缺陷探测率),在需求提出,力驳需求的可实现性,在需求阶段将不合理逻辑修正;在需求分析和开发代码的阶段,利用时间差系统梳理项目,临摹执行测试的步骤,编写详细的测试用例。协助将整体测试左移,把控项目进度,前紧后松,减少后期项目执行的各类风险的产生,提高系统测试阶段的效率。
这个管理包含自己、项目、团队
做乙方,multi-task是常态,我经常手上同时3、4个项目一起提测,一起运行的,不可能优哉游哉地让我做好一件事情再进入下一项,所以我必须要学会左右腾挪,尽最大可能提高自己的时间密度。那么有什么是可以跟大家分享的实操技巧呢。
首先,制定日计划,开启一天工作前,把自己今天需要做的大小事项,每项大概需要花费多少时间一一记录在我们的to do list中, 一目了然。(实际工作中我们会有一个dingding在线文档可以生效该功能)
有些工作可能我花费个半小时、一小时可以完成的,比如有些简单的遗留bug的复测,这样的工作我会优先做完,然后在我的to do list中划掉;那有些工作需要我重点攻坚的,那我就会拿出3、4个小时的完整时间来沉浸式完成,如整体的项目需求分析。我在单位时间的效率是较高的,因为我能很快地专注到我所做的工作当中,进入到一个心流模式。
敏捷工作方法,确认最小可交付物能到什么程度。先完成,再完美。以我在编写测试用例的为例子,我是不奢求一开始就尽全力覆盖所有的功能点的测试。我会现在xmind中罗列、拼凑出bullet point(要点),System functions(具体功能)。以实名认证为例,我会先罗列出项目所需支持的实名认证的各种方式;再深入一层,这几项在测试环境的业务流程要涉及哪些测试数据;再进一步拆解,从反向的测试数据、流程去验证整个实名认证代码的系统逻辑性是否都有覆盖到。简单说就是我会把框架完成之后再去缝制外衣,再去丰富内层,注入血肉,这是一个井然有序的过程
我负责的是一个测试小团队,团队只有三人,但我们的工作一向都是有序进行,我们之间的关系相辅相成。展开说,团队管理要点如下