熬夜肝出 3w 字测试开发学习路线
Posted C语言与CPP编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了熬夜肝出 3w 字测试开发学习路线相关的知识,希望对你有一定的参考价值。
本文将从薪水,职业规划,测试理论基础,自动化测试基础,常用自动化框架,计算机基础及 Python 高频面试题,测试相关高频面试题出发,详细内容如下,希望能对大家有所帮助。
薪水
我把它放在最前面,让大家能有一个基本的了解。综合下来,应届生在互联网公司的测开岗位薪水在 22~25 之间。
前景
我咨询身边认识的同学关于测开的前景。
测试的发展路线为两条,一条是业务型测试,另一个是技术型测试。业务型测试比较好理解,更加偏向业务,很可能最开始是从事测试方面的工作,后面去专门做了业务,其大概路线为功能测试,业务专家,行业业务专家,行业业务发展专家等,超级遥远的路罗。
对于技术型测试,更加偏向技术。从功能测试到测试开发,我遇到过一个测试,将开发的 Bug 揪出来就算了,还指导开发修改逻辑,哈哈哈哈哈哈,笑死我。其路线如下图哦
左侧为业务型测试,在工作中遇到一个姐姐,在银行外包大概工作了11年,后面转为行内的业务,甲方爸爸罗。当然是非常不容易的,所需要的付出不亚于走技术路线,不过你的业务路线会把自己的职业选择固定在某一个特定的领域。
右边是技术路线,职业选择还是挺广的了,功能测试,接口测试,性能测试,安全测试等等,也是面试的考察点,目前来看,纯粹的功能测试太少太少,几乎濒临淘汰罗,那么测试开发成为本文着重会说的复习内容。
测试开发本质
测试开发的本质是助力业务成功。感觉很多同学一上来就是学习编程技术,技术学习比较枯燥,计算机基础知识不扎实,很快就陷入了基础知识的泥沼。
在我看来了解基础理论后,学习 Python,Git 等必备技巧,熟悉一门自动化框架就可以解决测试相关的面试了。
软件测试存在的意义
通过一系列测试活动,「提前」发现和定位软件产品质量的薄弱环节,并倒逼开发人员修正,从而保证交付的软件质量满足客户需求。
有研究表明,越早发现软件中存在的问题,开发费用就越低,软件质量越高,软件发布后的维护费用越低。因此,提前发现和定位问题极为重要,而在软件开发的整个历程中,越是新兴的软件开发模型,越重视「提前测试」。提前测试可以使得在需求分析时期就可发现的错误,不必等到开发完成才被发现。
测试伴随着软件开发模型的演进
说到开发模型,从软件发展来看,比较典型的有瀑布模型,V 模型和 W 模型以及 敏捷开发模型。并不是说开发模型的选择越新越好,需要根据项目的具体情况而选择。
瀑布模型
我们知道,瀑布模型的主要特征在于项目完全按照阶段划分,只有前一阶段完成,才能开始下一阶段。具体到测试活动,则只能在全部编码完成后、发布之前执行,在这种开发模型中,测试活动被完全后置了,测试仅仅是编码后的一个活动阶段,测试的重要性没有被凸显出来。
V 模型
基于此,V 模型出现了。V 模型在整个开发过程中,不仅相对清晰地划分了测试活动的不同级别,还将其不同级别的测试活动与软件开发各阶段清晰地对应起来,强调了测试在整个开发过程中的重要性。但在 V 模型中,测试依旧是编码之后才开始的,测试介入时间还是太晚。比如,需求分析阶段出现的问题,要等到系统测试阶段才能发现。
W 模型
为了弥补这一缺点,V 模型的进一步深化版,即W 模型出现了。从 W 模型的示意图中,可以看到,W 模型是把 V 模型左边的每一个活动都加了一个测试设计活动,体现了“尽早和不断地进行测试”的原则。
敏捷模型
敏捷过程模型”是指基于迭代开发的软件开发方法。敏捷方法将任务分解为较小的迭代, 或者部分不直接涉及长期计划。在开发过程的开始就确定了项目范围和要求。事先明确定义了有关迭代次数, 每次迭代的持续时间和范围的计划。
每次迭代都被视为敏捷流程模型中的短时间”框架”, 通常持续一到四个星期。将整个项目分成较小的部分有助于最大程度地降低项目风险, 并减少总体项目交付时间要求。每次迭代都涉及一个团队, 在整个软件开发生命周期中进行工作, 包括计划, 需求分析, 设计, 编码和测试, 然后再向客户展示有效产品。
职业生涯
软件测试开发流程
需求分析
在测试前拿到产品需求文档,进行需求分析及需求评审前先对需求文档进行详细的阅读,对有疑问的地方进行标注。
具体可从以下进行:
分析产品功能点
产品核心竞争力
Kano模型、马斯洛需求分析、多问几个为什么、上下文分析法
制订测试用例(重要)
工欲善其事,必先利其器;对测试而言,测试用例就是器,做好了才能把好关
使用思维导图列举测试大纲,尽量发散,想到什么就写什么,;先放后收,对知识点进行总结和归纳,标记重点测试模块,删除冗余及重复测试点。
可使用边界值法、等价类划分法、错误推测法、因果图法等设计案例
根据测试大纲制定测试用例,需包含模块名、测试优先级、操作步骤、期望结果、测试结果、备注
评审测试用例
测试作为主导,联合开发、项目经理、PM进行测试用例评审
可先讲解测试大纲,让开发、项目经理、PM心中对测试用例有个大概;后再进行详细测试用例讲解
执行测试
根据测试用例执行测试
发现问题保留现场,记录测试方法,通知开发解决问题
覆盖测试用例之外若有时间可进行探索性测试
提交 Bug 并推动 Bug 解决
在Bug管理工具上提交Bug,详细记录测试步骤
根据Bug严重程度划分Bug等级:致命、严重、一般、提示
推动开发解决问题,记录问题进展,一般聊天沟通,若问题严重则需通过邮件推动解决
回归测试
对已修复的 Bug 进行验证
对 Bug 所在模块进行基本功能测试;整体进行冒烟测试,确保不会因为修改 Bug 而引起其他功能出现问题
编写并提交测试报告
可使用金字塔原理设计测试报告,先总后分,上级统领下级,下级推导出上级,环环相扣
对Bug进行汇总,筛选出各个等级的Bug存活情况
制订Bug发现及解决曲线图,一般版本正常应是前期多,后期收敛,存活的是级别较低的Bug
总结归纳版本情况,评估发布与否
软件测试方法
白盒测试
概念:关注程序代码的具体细节,根据软件内部代码的逻辑结构分析来进行测试。主要是通过阅读程序代码或者通过使用开发工具中的单步调试来判断软件质量。关注代码的实现细节。主要对程序模块的所有独立执行路径至少测试一遍、对所有的逻辑判定,取“真”或“假”的两种情况都要测试一遍,循环边界和运行界限内执行循环体等等
测试用例设计方法:逻辑覆盖、循环覆盖、基本路径覆盖、判定覆盖
优点:增大代码的覆盖率,提高代码的质量,发现代码中隐藏的问题
缺点:系统庞大时测试开销很大,难以测试所有运行路径;测试基于代码,只能验证代码是否正确,而不晓得代码设计是否合理,可能会遗漏某些功能需求
黑盒测试
概念:不考虑其内部结构,即具体代码实现,检测软件的各个功能能否得以实现,确认软件功能的正确性,依靠软件说明书来判断测试用例,关注具体的客户需求及软件功能。黑盒测试主要是为了发现:1.是否有不正确的或者遗漏的功能;2.输入是否能输出正确的结果;3.性能上是否满足要求
优点:①较为简单,不需要了解程序内部的代码及实现,与软件内部实现无关;②从用户角度出发,实际考虑用户使用的功能及可能出现的问题
缺点:不可能覆盖所有的代码,覆盖率较低
测试用例设计方法:边界值分析法、等价类划分、错误猜测法、因果图法、状态图法、测试大纲法、随机测试法、场景法
等价类
输入域的各子集中,各个输入数据对于揭露程序中的错误都是等效的。
等价类划分:将全部输入数据合理划分成若干个等价类,在每一个等价类中取一个数据作为输入条件,就可以用少量代表性测试数据取得较好的测试结果。分为有效等价类(合理、有意义的输入数据构成的集合)和无效等价类
边界值分析法:大量错误是发生在输入输出范围的边界上,选定测试用例时应该选取正好等于、刚刚大于、刚刚小于边界值的值作为测试数据,而不是选取等价类中的任意值,作为对等价类划分的补充
错误猜测法:基于经验和直觉推测,列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据这些情况选择测试用例
因果图法:考虑输入条件之间的相互组合,也考虑输出结果对输入条件的依赖关系。原因即为输入条件或者输入条件的等价类,结果即为输出条件,把因果转换为决策表,为决策表中的每一列设计测试用例。
场景分析法:根据用户场景来模拟用户的操作步骤
大纲法:着眼于需求。将需求转换为大纲的形式,大纲表示为树状结构,在根和叶子节点之间存在唯一路径,大纲为每条路径定义了一个特殊的输入条件集合,用于测试用例。
随机测试法:不考虑任何用例和需求,完全站在用户的角度对产品进行测试
灰盒测试
关注输入输出的准确性,也关注内部的代码,但是没有白盒测试那么详细完整。
动态测试:
实际运行被测程序,输入相应的测试用例,检查运行结果与预期结果的差异,从而验证程序的正确性、有效性和可靠性,并且分析系统运行的效率和健壮性。
α测试:
一个用户在开发环境下的受控测试,模拟实际操作环境
β测试
多个用户在实际使用环境下进行的测试,如一些软件的公测
冒烟测试
在大规模测试之前,先对软件的基本、核心、主要功能进行测试,节省资源
回归测试
开发修正完代码后再回过头来做测试
随机测试
跳出思维的限制,没有思想、没有步骤地随机进行测试
探索测试
有思想,有步骤地测试一些复杂的、不常用地功能
为什么引入自动化测试
自动化测试是将自动化工具和技术应用于软件测试,旨在减少测试工作,更快,更经济地验证软件质量。有助于以更少的工作量构建质量更好的软件。
许多公司多多少少都在做自动化测试,但手动测试仍然占主要的比例,因为有些团队不知道如何在开发过程中更好的利用自动化测试来替代手动测试。
手工测试通常是工程师仔细的执行预定义的测试用例,将执行结果与预期的行为进行手工比较并记录结果。每次源代码更改时都会重复这些手动测试,由于都是人为参与,这个过程中很容易出错。
在组织中引入自动化测试时,需要投入大量财力和时间。然而,一般没有太多的财务回报,至少在小规模开始时没有。因此许多公司选择开源测试自动化工具,特别是在开始引入自动化测试的阶段。
通常,软件公司害怕投资自动化测试,不是因为负担不起这个投入,而是因为他们担心的回报不会像预期的那样,或者根本不会产生积极的投资回报率。
1. 降低成本(特别是问题出现时的成本)
如前所述,开始自动化测试的初始成本并不高,比如选用免费的开源工具。但是,一旦您的组织全面展开自动化测试,您就会希望投资更好的工具、更好的服务器,雇用人力来维护基础设施等。这些成本绝对不是无关紧要的。
自动化测试不会自动生成。创建有价值的自动化测试需要花费时间和精力,而且不会在一夜之间发生。
如果您想证明引入自动化测试的合理性,不能只关注财务回报,而应考虑应用出现问题导致的隐性成本。例如一个问题在手动测试没有发现而出现在产品环境中,公司会花多少钱?你是否会失去客户?需要花多少时间、资源和资金来纠正这种情况?
如果每次对代码进行更改时,都重复执行一组非常强大的测试套件,可以降低问题出现在产品环境的风险。自动化测试有助于在软件开发生命周期的早期发现错误,从而降低交付故障软件的风险。
说到底,向市场提供高质量的产品重要性远大于任何其他类型的节省。
2. 节省时间
虽然初期建立自动化测试需要花费大量的时间和人力,但是一旦自动化测试建立了,您就可以重用这些测试。自动化测试的执行速度明显快于手动测试,不易出错,且节省人力。
在日常的代码修改过程中,您可以在每次提交时执行自动化测试,而不必通过设置环境或记住执行每个测试的步骤来持续执行手动步骤。一切都是自动完成的。
只要首次设置完成后,就可以重复运行你的自动化测试,从而将重复的手动测试时间从数周缩短至数小时。
同样一旦编写好,测试可以执行任意次。与手动测试仪不同,测试也可全天候,无人值守的执行。
在软件开发团队中,通常的做法是每天多次(通常是每次提交)运行基本单元测试,并且每天在下班后执行耗时的集成测试和UI测试。
3. CI和DevOps
自动化测试构成任何持续集成或DevOps设置的基础。从本质上讲,CI(持续集成)和DevOps都依赖于“Fail fast, Fail early”的理念。对代码库的每次提交都将自动进行测试,并将结果报告给开发人员。开发人员优先修复任何导致构建失败或导致主要测试失败的错误,确保主线代码始终按预期工作。
4. 准确性和可靠性
由于运行每个测试涉及多个先决条件,手动测试容易出错。另外每个测试可能需要不同的执行顺序。
毕竟手动测试人员是人类,人有不善于执行重复枯燥工作的特点,因此可以预料手动测试不会精确并有一定的几率出错。这会导致不准确的结果反馈到开发团队。
自动化测试每次都执行相同的步骤,不仅精确,而且结果可在最短的时间内提供给所有相关人员。
可靠性的另一个方面是在不同服务器上重新执行相同的测试。这使得能够快速验证测试是否在所有服务器上按预期运行,从而排除了服务器配置问题的可能性。
4. 性能测试
性能负载测试可确保您的应用程序可以处理预期和意外的用户负载。
如果您当前只在项目中使用手动测试方法,则负载测试可能会推迟到开发周期结束。按照敏捷方法和持续集成理念,应及早地进行性能测试,但现实是很大一部分项目团队执行做这个测试的时间太晚,最终导致产品发布推迟。
自动化性能测试能够同时运行数千个测试,模拟数百万用户,所有这些用户手动测试几乎都是不可能的。
5. 增加对软件的信心
敏捷方法建议使用sprint,即短周期的迭代。每个sprint通常2-3周。这需要一种新的方式来组织测试工作并要求更高的效率。
每个sprint都专注于开发一组小功能,但必须在其结束的时候提供较完整的新功能特性,还包括之前sprint的所有功能特性。如果没有适当的测试,在不破坏之前正常工作的功能特性的情况下提供全功能系统的风险很高。在每个sprint中反复手动测试所有功能会效率低下。
这也是自动化测试最大的好处。自动化测试并能够在每个sprint中快速重复测试,可以确保所有事情都按预期工作。
6. 衡量质量指标
可用于自动化测试的扩展和工具提供了测量许多代码质量指标的功能,例如代码覆盖率(即实际测试的代码百分比),技术债,代码语义检查等。
通常,当测试作为持续集成或DevOps工作流程的一部分执行时,可同时获取这些方面的测量数据。
之所以能够测量这些指标,是因为自动化测试代码本身与产品代码共存,通过在自动构建阶段解析源代码,能提供在几分钟内测量巨大代码库质量的机会。这在手动测试中根本不可能。
小结
如果您的产品质量是您的首要目标,我强烈建议您使用自动化测试作为日常开发实践的一部分。它将确保您的应用程序得到正确测试,并为研发、管理人员和客户提供信心。
自动化测试需要前期投入,并且需要花时间进行开发。这些投入会得到长期的回报:可以减少工作量,消除手动测试的错误,提高准确性,最终节省成本和时间。
总的来说,自动化测试是一种比手动测试更快获得故障反馈的方法,符合“快速失败,早期失败”的原则。它有助于实现手动测试无法提供的质量。在自动化测试中,
行为驱动的自动化测试
现已广泛为研发团队所接受,基于行为驱动(BDD)的测试脚本具有上手快、易维护、方便所有stakeholders沟通等特点。
如果您还没有一款合适的自动化测试工具来确保软件质量,您可以了解
自动化测试框架包含哪些模块
一个比较成熟的测试框架通常会包含 4 个部分,分别为基础模块,管理模块,统计模块和运行模块。
基础模块
造房子要稳固需要良好的地基。如果把自动化测试框架比作一辆汽车,那么自动化测试基础模块就是那四只轮胎,没有它们,这辆汽车寸步难行,它们一般包括如下部分。
可重用的组件
一般来说用来降低开发成本,常见有日志模块,时间模块等
配置文件
通常会包含测试环境的配置和应用程序的配置。其中测试环境配置用来减少环境版本切换,从开发到上线
管理模块
管理模块就仿佛是车中的内饰,它对测试框架的使用操作体验有着直接的影响,分为测试数据管理和测试文件管理
测试数据管理
测试数据一般是测试用例用到的各种测试数据,他们是为了验证业务正确性而构造,每一组的测试案例通常会对应一对或多对测试数据。测试数据的创建又分为实时创建和事先创建,
实时创建是测试代码运行的时候才生成测试数据。好处是测试数据和测试代码解耦合,测试人员不用关心创建过程和业务调用链,通常用在测试的公用功能上。
事先创建,是指测试代码运行前就准备好的数据文件,其好处是数据拿来即用,几乎不耗费时间,由于没有业务调用,所以这在一定程度上减少了调用失败的风险;坏处则是数据文件本身需要维护,以保持可用性和正确性。
测试文件管理
测试文件管理就仿佛是车子的外观,给人第一印象。一个测试用例通常需要包含三个文件,分别是Page类文件,测试类文件和对象库文件。
这三个文件共同描述一个完整的测试用例。测试文件的结构清晰有助于他人理解测试框架的设计思想
运行模块
运行模块为测试框架的发送机,用于测试用例的组织和运行,通常包含下面几个部分
测试用例调度,驱动机制
错误恢复机制
测试框架应该具有一定的错误恢复机制,测试案例执行过程中,可能出现代码运行错误或环境导致的错误。
持续集成支持
测试框架应该能够和 CI 系统低成本集成,包括通过用户输入参数指定运行环境、测试结束后自动生成测试报告等。
统计模块
统计模块相当于车子的品质和口碑。一个完整的统计模块,可以告诉你当前测试有没有 Bug,还能分析软件质量的变化情况,统计模块一般包含下面几个模块
测试报告
测试报告应该全面,包括测试用例条数统计、测试用例成功/失败百分比、测试用例总执行时间等总体信息。其中,对于单条测试用例,还应该包括测试用例 ID、测试用例运行结果、测试用例运行时间、测试用例所属模块、测试失败时刻系统截图、测试的日志等信息。
日志模块
测试框架应该包括完善的日志文件,方便出错时进行排查和定位。
常用的测试框架类型
有的时候,面试官可能也会用你知道哪些测试框架,测试框架分为这样几种
模块化测试框架
模块化测试框架是利用 OOP 思想和 PO 模式改造而来的框架。
模块化测试框架把整个测试分为多个模块,模块化有以下几个特征:
我们将一个业务或者一个页面成为一个 Page 对象;
这个 Page 对象,我们以一个 Page 类来表示它;
这个 Page 类里存放有所有这个 Page所属的页面对象、元素操作;
页面对象和元素操作组成一个个的测试类方法,供测试用例层调用。
简单来说,使用了 PO 模式的框架就可以叫作模块化测试框架。
模块化测试框架的好处在于方便维护,你的测试用例可以由不同模块的不同对象组成;
坏处在于你需要非常了解你的系统及这些模块是如何划分的,才能在测试脚本里自如地使用,否则你就会陷入重复定义模块对象的循环里。
数据驱动框架
数据驱动框架主要是解决测试数据问题。
在测试中,我们常常需要为同一个测试逻辑,构造不同的测试数据以满足业务需求,这些测试数据可以保存在测试代码里,也可以保存在外部文件里(包括 Excel、File、DB)。
数据驱动框架的精髓在于,输入 M 组数据,框架会自动构造出 M 个测试用例,并在测试结果中把每一个测试用例的运行结果独立展示出来。
在 Python 架构里,最出名的数据驱动框架就是 DDT。
关键字驱动框架
当把一系列代码封装为要给关键字,在测试的过程中,通过组合关键字的方式来生成测试用例,而不关心关键字如何运作的,这种为关键字驱动框架。
混合模型
并不一定要选择上面的三种框架之一,需要根据需求灵活的选择测试框架,在工作中可能经常需要糅合不同的框架模型,这样的模型就叫做混合模型。
测试框架设计原则
首先是清晰明了,学习成本低
其中包含代码规范和模块清晰明确。
通用性强,可维护,可扩展
对错误的处理能力强
错误处理机制,能高效解决。系统日志清晰,方便调试。
运行效率高且功能强大
支持测试环境切换,支持外部数据驱动,支持顺序并发,远程运行,报告完备详尽。
支持版本控制和持续集成
版本控制回溯复盘,持续集成全局出发
如何设计一个不错的测试案例
「好的」测试用例一定是一个完备的集合,它能够覆盖所有等价类以及各种边界值,而跟能否发现缺陷无关。
一个“好的”测试用例,必须具备以下三个特征 。
整体完备性 :「好的」测试用例一定是一个完备的整体,是有效测试用例组成的集合,能够完全覆盖测试需求。
等价类划分的准确性 :指的是对于每个等价类都能保证只要其中一个输入测试通过,其他输入也一定测试通过。
等价类集合的完备性 :需要保证所有可能的边界值和边界条件都已经正确识别。
三种最常用的测试用例设计方法:等价类划分法、边界值分析法、错误推测方法。
第一,等价类划分法
我们只要从每个等价类中任意选取一个值进行测试,就可以用少量具有代表性的测试输入取得较好的测试覆盖结果。现在,我给你看一个具体的例子:学生信息系统中有一个考试成绩的输入项,成绩的取值范围是 0~100 之间的整数,考试成绩及格的分数线是 60。为了测试这个输入项,显然不可能用 0~100 的每一个数去测试。通过需求描述可以知道,输入 0~59 之间的任意整数,以及输入 60~100 之间的任意整数,去验证和揭露输入框的潜在缺陷可以看做是等价的。那么这就可以在 0~59 和 60~100 之间各随机抽取一个整数来进行验证。这样的设计就构成了所谓的“有效等价类”。
你不要觉得进行到这里,已经完成了等价类划分的工作,因为等价类划分方法的另一个关键点是要找出所有「无效等价类」 。显然,如果输入的成绩是负数,或者是大于100的数等都构成了“无效等价类”。
在考虑了无效等价类后,最终设计的测试用例为:
有效等价类1:0~59之间的任意整数;
有效等价类2:59~100之间的任意整数;
无效等价类1:小于0的负数;
无效等价类2:大于100的整数;
无效等价类3:0~100之间的任何浮点数;
无效等价类4:其他任意非数字字符。
第二,边界值分析方法
边界值分析是对等价类划分的补充,你从工程实践经验中可以发现,大量的错误发生在输入输出的边界值上,所以需要对边界值进行重点测试,通常选取正好等于、刚刚大于或刚刚小于边界的值作为测试数据。我们继续看学生信息系统中“考试成绩”的例子,选取的边界值数据应该包括:-1,0,1,59,60,61,99,100,101。
第三,错误推测方法
错误推测方法是指基于对被测试软件系统设计的理解、过往经验以及个人直觉,推测出软件可能存在的缺陷,从而有针对性地设计测试用例的方法。** 这个方法强调的是对被测试软件的需求理解以及设计实现的细节把握,当然还有个人的能力。
错误推测法和目前非常流行的“探索式测试方法”的基本思想和理念是不谋而合的,这类方法在目前的敏捷开发模式下的投入产出比很高,因此被广泛应用。但是,这个方法的缺点也显而易见,那就是难以系统化,并且过度依赖个人能力。
总结:在我看来,深入理解被测软件需求的最好方法是,测试工程师在需求分析和设计阶段就开始介入,因为这个阶段是理解和掌握软件的原始业务需求的最好时机。
计算机基础
计算机基础部分,如果时间紧张,可以直接看计算机网络和数据库的面试总结。如果想要更加精细的去学习相关的内容,可以参考我之前写的那篇2021C++学习路线,其中的计算机基础部分是通用内容。到
Python基础
这里推荐大家看看《python入门到实践》这本书,看完基本上就能使用 Python 了。
我们需要了解什么是 Python,它和 Java/C++有什么不一样,基本数据类型有哪些,Python 控制流(for,while)怎么用。
Python 中 包管理,函数,模块之间的关系等等。当了解了基础知识以后,就可以去看看匿名函数(lambda)如何使用,自省和反射是什么意思,闭包的基本概念,如何实现要给装饰器等等。这里总结了一部分题目,可以参考,如果不明白或不清楚或觉得不对的地方,大家一定要记的去查阅哦。
什么是Python的命名空间?
在Python中,所有的名字都存在于一个空间中,它们在该空间中存在和被操作——这就是命名空间。它就好像一个盒子,每一个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面寻找相应的对象。
主(main)函数的作用
作为整个程序文件的入口。
调试代码的时候,在if name__ == ‘__main’中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!
cookie和session的关系和区别
由于 HTTP 协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是 Session.典型的场景比如购物车,当你点击下单按钮时,由于 HTTP 协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的 Session,用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个 Session 是保存在服务端的,有一个唯一标识。在服务端保存 Session 的方法很多,内存、数据库、文件都有。集群的时候也要考虑 Session 的转移,在大型的网站,一般会有专门的 Session 服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如 Memcached 之类的来放 Session。
思考一下服务端如何识别特定的客户?这个时候 Cookie 就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现 Session 跟踪的,第一次创建 Session 的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个 Session ID,以后每次请求把这个会话 ID 发送到服务器,我就知道你是谁了。
有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做 URL 重写的技术来进行会话跟踪,即每次 HTTP 交互,URL 后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
Cookie 其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到 Cookie 里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是 Cookie 名称的由来,给用户的一点甜头。
所以,总结一下:
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
new 和 init 的区别
new:创建对象时调用,会返回当前对象的一个实例
init:创建完对象后调用,对当前对象的一些实例初始化,无返回值
调用顺序:先调用new__生成一个实例再调用__init方法对实例进行初始化,比如添加属性。
参数传递机制
如果实际参数的数据类型是可变对象(列表、字典),则函数参数的传递方式将采用引用传递方式。如果是不可变的,比如字符串、数值、元组,他们就是按值传递。
迭代器
迭代器是访问集合元素的一种方式,他的对象从集合的第一个元素开始访问,直到所有元素被访问完结束,用iter()创建迭代器,调用next()函数获取对象(迭代只能往前不能后退)。
两者区别:
创建/生成,生成器创建一个函数,用关键字yield生成/返回对象;迭代器用内置函数iter()和next()
生成器中yield语句的数目可以自己在使用时定义,迭代器不能超过对象数目
生成器yield暂停循环时,生成器会保存本地变量的状态;迭代器不会使用局部变量,更节省内存
PYTHONPATH变量是什么
Python中的环境变量,用于在导入模块的时候搜索路径。因此它必须包含Python源库目录以及含有Python源代码的目录。
模块和包
模块:python中包含并有组织的代码片段,xxx.py的xxx就是模块名
包:模块之上的有层次的目录结构,定义了由很多模块或很多子包组成的应用程序执行环境。包是一个包含init.py文件和若干模块文件的文件夹。
库:具有相关功能模块的集合,python有很多标准库、第三方库…
yield
保存当前运行状态(断点),然后暂停执行,即将函数挂起
将yeild关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用,当使用next()、send()函数让函数从断点处继续执行,即唤醒函数。
args和*kwargs的含义
不知道向函数传递多少参数时,比如传递一个列表或元组,就使用*args
def func(*args):…
Func(1,2,3,4,5)
不知道该传递多少关键字参数时,使用 **kwargs 来收集关键字参数(keyword argument)
python def func(**kwargs):… Func(a=1,b=2,c=3)
Python垃圾回收机制
(自动处理分配回收内存的问题,没用了内存泄漏的隐患),以引用计数机制为主,标记-清楚和分代收集两种机制为辅
计数机制就是 Python 中的每一个对象都有一个引用计数的值,当有引用的时候,这个值会增加,引用他的对象被删除时,这个值减小,引用计数的值为0时,该对象生命结束,Python 会把这段内存自动回收。(缺点,循环引用,如果 l1 和 l2 相互引用,没用其他的对象引用他们,这两段内存永远无法被回收)
Python如何内存管理
引用计数:python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
垃圾回收:python会检查引用计数为0的对象,清除其在内存占的空间;循环引用对象则用一个循环垃圾回收器来回收
内存池机制:在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。这就意味着Python在运行期间会大量地执行 malloc 和 free 的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
Python 提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
Python 中所有小于 256 个字节的对象都使用 pymalloc 实现的分配器,而大的对象则使用系统的 malloc。另外 Python 对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
深拷贝、浅拷贝和等号赋值
深拷贝:新建一个对象,把原来对象的内存完全复制过来,改变复制后的对象,不会改动原来内存的内容。(两个对象在复制之后是完全独立的对象)
等号赋值:相当于为原来的对象打一个新的标签,两个引用指向同一个对象,修改其中的一个,另一个也会产生变化
浅拷贝:两种情况,1. 浅拷贝的值是不可变对象(数值、字符、元组)时,和等于赋值一样,对象的id值和浅拷贝原来的值相同;2. 如果是可变对象(列表、字典等),a. 一个简单的没有嵌套的对象,复制前后的对象相互之间不会影响,b. 对象中有复杂子对象,如列表嵌套,如果改变原来的对象中复杂子对象的值,浅拷贝的值也会受影响,因为在浅拷贝时只复制了子对象的引用(只拷贝父对象)。
Python有什么优势
解释型,语法简单易懂,可读性强
有很多库可以用,可以让我们站在巨人的肩膀上简单的实现想要的功能
可扩展,和其他编程语言或其他软件有可连接的接口
免费开源、可移植
自动内存管理,让程序员可以专注于代码的实现
Python 缺点
他的可解释特征使其运行速度变慢
动态语言的特点可能会增加运行时错误。
面向对象和面向过程的区别
面向对象是把构成问题的事务分解成各个对象,建立对象来描述某个事务在解决问题的步骤中的行为;
面向过程是分析出解决问题所需要的步骤,然后用一些函数把这些步骤一步步实现,使用的时候依次调用函数就行了。
写一个装饰器
import functools
import time
def print_run_time(func):
@functools.wraps(func) def wrapper(*args,**kw):
local_time=time.time()
func(*args,**kw)
t=time.time()-local_time
print(t)
return wrapper
@print_run_time
def test(x):
for i in range(1000):
print(x,end='')
print('\\n')
return x
test(1)
python 装饰器@staticmethod和@classmethod区别和使用
@classmethod:类方法,类方法是给类用的,类在使用时会将类本身当做参数传给类方法的第一个参数,python为我们内置了函数classmethod来把类中的函数定义成类方法。
@staticmethod:静态方法
用上面两个装饰器就可以不用在实用类前对类进行实例化了,
@property:将一个实例方法提升为属性,便于访问
Git
如果说功能测试工程师的日常工作是被测试用例文档包围,那么测试工程师则从代码提交说起。
在当前高度协作的今天,测试开发的任务也是各个负责相应的模块,每个模块不同人负责,那么可能就出现下面这些问题
你和别人负责不同的模块,代码都提交后入俄整合
如果你在修改一份公共代码,别人也在修改,如何提交和保存
如果想看人家提交的历史记录,如何回滚
说白了,我们需要一个版本控制系统来跟踪我们的代码,从而更好地解决冲突。
为啥大家都用 Git呢
高效的数据存储方式
和其他的版本控制软件不同的是,Git并不以文件表更列表的方式存储信息,而是采用了快照流的方式对信息进行存储。
在 Git 提交更新的时候,Git会对项目全部文件创建一个快照并保存这个快照的索引。当再次提交,更新的时候,如果存在没有修改的文件,那么 Git 只保留一个链接指向之前存储的文件,而不再重新存储该文件,这样就提高了存储效率。
几乎所有操作在本地执行
在 Git 中,绝大部分的操作访问本地文件和资源都无需联网。
具备数据完整性保障
在 Git 中,任何操作在被操作前都需要使用 SHA-1 散列计算校验来保障数据的完整性。
Git 的工作流程
在 Git 中,项目文件可能处于这样三种形态
已修改:表示修改了文件但还没有保存到数据库
已暂存:表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中
已提交:表示数据已经安全地保存在本地数据库中
Git 项目的三个节点
对应上面三种状态,会有三个阶段,为工作区,暂存区和 Git 目录。
工作区
工作区是从 Git 仓库提取出来的数据,也就是我们本地看到的代码目录,这里改动的代码都在已修改状态。
暂存区
暂存区是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。当处于已修改状态的文件被放入暂存区(Git Add)时,这些文件则会变为已暂存状态。
Git 目录
Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。从其他计算机克隆仓库时,复制的就是这里的数据。当暂存区的文件被提交(Git Commit),则这些文件属于已提交状态。
Git 实践
通过上方的内容了解 Git 以后,最好动手实践一波。
安装 Git
Git 基本设置
流程
在公司中,通常都通过 Github 企业版或 GitLab 进行托管,那么测试开发使用 Git 流程大概如下
通常在本地 Feature 分支进行开发,随后提交测试,本地测试完成则 pull request方式提交代码,测试验证,验证完成后 Github 会根据条件自动出发测试验证流程,代码 Merge,通过后 Merge 到 Master。
如果是新项目,如何初始化 Git 项目呢
首先通过 Git init 初始化项目,此时 Git 仓库为空的,那我们就新建一个文件叫做 lanlan.py,写完以后通过 git add 的方式提交到暂存区。
如果想删除这个文件,那么可以通过 git rm 来删除某个文件。
如果你想要查看当前版本库的状态,可以使用 git status,它将列出文件夹在工作区和暂存区的状态。
如果想要将暂存区的改动提交到本地版本库,那就可使用 git commit -m,这里的 -m 后面一定要记得些提交的注释哟。
如果想要本地的这份代码提交到远程进行协作开发,就需要使用下面的语句
#如下语法用来添加一个远程仓库
$ git remote add [shortname] [url]
#将本地仓库lagouTest和远程仓库建立连接
$ git remote add origin https://github.com/yourCompany/lagouTest.git
既然是团队开发了,那么就先把本地版本代码传到远程库,这样其他的开发人员就可以拉取最新的代码
git push -u origin master
想要获取最新的代码,就需要使用 git clone 拉去最新代码。
可是通常不会在 master 上进行开发,而是需要切换分支,使用 git checkout -b name 的方式切换分支。
使用 Git 的时候,可能遇到哪些问题呢
如何查看提交的历史
如果想要查看某个文件的提交历史,可以使用 git log filename 或 git log lanlan.py 的方式查看
如果本地正在开发,远程的 master 已经更新了,如何更到本地分支
# 假设本地feature分支为newFeature
# 首先需要提交本地分支newFeature的改动至代码仓库
$ git add .
$ git commit -m "本地分支修改comments"
# 然后,执行git merge
$ git merge master
# 最后,再次提交
$ git add .
$ git commit -m "merge master 分支"
提交的时候出现冲突怎么办
当多人更改同一文件的时候就会出现冲突,此时 git 会列举出冲突的内容,可以通过手动的方式保留哪个版本,然后 git add 和 git commit 的方式再次提交
当你正在进行分支开发时,接到一个紧急任务,如何将当前的改动保留和后续恢复?
当你的 feature 分支开发了一半,然后接到了紧急任务需要支持,但是你又不想把功能不完善的代码提交到代码仓库,此时可以使用 git stash 命令。
# 如果你要切换新分支但是有未保存的更改使用git checkout -b会报错。此# 时可以通过git stash将所有未提交的修改(工作区和暂存区)保存至堆栈# # 中,可用于后续恢复.
$ git stash
# 等你想恢复你保存的改动时,执行git stash pop。 它将缓存堆栈中的第一个stash删除,并将对应修改应用到当前的工作目录下。
$ git stash pop
本地提交已提交到暂存区,但是不想要了怎么办?
假设你的某次改动已经提交到暂存区,还没有 push,但是你想丢弃这个改动,可以采用如下办法:
$ git reset --hard HEAD
上线后有问题,代码需要回退怎么办?
$ git revert HEAD
$ git push origin master
Linux
之前那一篇 3w 字的 Linux总结看完就差不多了哦,链接在此,在星球中同样是有 PDF。
Docker
Docker基础部分在之前的文章也给出了,大家可以花时间去学习一波。
Docker容器圈简介
第二趴---Docker基本操作
数据库
数据库计划的是三个部分,第一部分数据库基础之前也完成了,不少小伙伴也打卡学习完了基础部分,下个周会给出数据库索引的面试题,一起加油哦。
操作系统
CICD
持续集成
持续集成(Continuous integration,简称CI),简单来说持续集成就是频繁地(一天多次)将代码集成到主干。
每次集成都通过自动化的构建(包括编译、发布、自动化测试)来验证,从而尽快地发现集成错误。
持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,可以确定新代码和原有代码能否正确地集成在一起。
持续集成的好处:
快速发现错误,每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易;
防止分支大幅偏离主干,如果不经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
持续集成的目的
让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
持续集成并不能消除 Bug,而是让它们非常容易的发现和改正。
持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。
持续交付
持续交付(Continuous delivery)指的是:频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段
持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。
持续部署
持续部署(Continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。
持续部署则是在持续交付的基础上,把部署到生产环境的过程自动化。
持续部署的目标是:代码在任何时候都是可以部署的,可以进入生产阶段,持续部署的前提是能自动化完成测试、构建、部署等步骤。
Selenium面试题
之前给星球的小伙伴修改简历,发现想要面试自动化测试相关的岗位,然而基本上没有这方面的复习准备,项目经验也没有。如果大家需要相关的项目,也可以找我拿罗,我都放在星球了。
什么是Selenium?
Selenium是一个开源的web自动化测试框架,主要是基于web uI的自动化测试。现在的版本,逐步增加了对移动端的自动化测试。Selenium支持多种语言进行开发自动化测试脚本,有Java,python,C#,javascript等等。Selenium支持跨浏览器平台测试。
Selenium是否支持桌面应用软件的自动化测试。
Selenium不支持桌面软件的自动化测试,Selenium是根据网页元素的属性才定位元素,而其他桌面软件自动化测试工具是根据桌面元素的位置来定位元素,当然现在也有根据桌面元素的属性来定位的。
Selenium是否支持用例的执行的引擎。
引擎好比就是一个发动机。Selenium是没有关于测试用例和测试套件管理和执行的模块。我们需要借助第三方单元测试框架来实现用例管理和用例的执行。例如Java中有Junit或者testNG,Python中有unittest单元测试框架。
Seleinum是否有读取excel文件的库
没有,这里需要用到第三方工具。例如Apache POI插件。
Selenium有哪些组件?
最早的有Selenium IDE,IDE只支持安装在fiefox上一个插件,支持录制自动化脚本。还有
remote RC,和Grid 和webdriver。我们一般最重要的就是使用webdriver。
Selenium有什么限制或者缺陷
除了基于web的软件和mobile的程序,selenium不支持桌面软件自动化测试。软件测试报告,和用例管理只能
依赖第三方插件,例如Junit/TestNG和unittest。由于它是免费的软件,所以没有供应商去提供支持和服务,有问题,只能求助selenium社区。还有一个就是,selenium入门门槛可能有点高,需要具备一定编程语言基础的才能玩转。
在selenium中,有哪些不同定位元素方法
ID/className/Name/LinkText/PartialLinkText/Xpath/CSS selector
什么是imlicitlyWait
imlicitlyWait是隐式等待,一般在查找元素的时候使用。例如,我设置一个查找元素最大时间为10秒,使用了
imlicitlyWait后,如果第一次没有找到元素,会在10秒之内不断循环去找元素,知道超过10秒,报超时错误。
什么是expliciteWait
这个是显式等待,就是不管如何都是要等10秒,如果你设置了10秒超时,这个是selenium2的功能
在selenium3中,我暂时没有找到这个接口。
什么是线程等待
有时候,我们需要强制设置线程等待,Thread.sleep(2000),driver这个实例,就是当前的线程。
什么是pollingEvery
这个是设置个一段时间就去做一件事,例如下面设置隔一秒就去查找元素一次。
WebDriverWait wait = new WebDriverWait(driver,30);
wait.pollingEvery(1, TimeUnit.SECONDS);
driver.findElement(By.xpath("xxxx"));
你能解释下Selenium这个框架吗?
这个问题在面试中被问到的概率还是比较高的,
以上是关于熬夜肝出 3w 字测试开发学习路线的主要内容,如果未能解决你的问题,请参考以下文章
2021年底粉丝大馈赠,熬夜7天肝出这一份3000字性能测试学习笔记
从功能测试到自动化测试,携程大牛熬夜7天肝出这份5000字工作感悟!