面试官您好,我叫[你的名字],本科毕业于[你的学校],拥有三年的软件测试工作经验。
在过去的三年里,我专注于Web端和App端的电商项目测试,熟练掌握从需求分析、测试用例设计与评审、测试执行到缺陷跟踪管理的完整测试流程。
在技能方面:
- 功能测试:这是我最擅长的领域,我能独立负责核心业务模块,如电商中的订单、支付和优惠券模块,确保业务逻辑的正确性和用户体验的流畅性。
- 接口测试:我熟练使用Postman和JMeter等工具进行接口测试,能够独立编写接口用例,对接口的功能、数据交互和异常场景进行全面验证。
- 性能测试:我对性能测试有初步的涉猎,了解性能测试的基本流程和核心指标,如响应时间、TPS和并发用户数,并使用过JMeter进行简单的压力测试。
- 自动化测试:我具备一定的自动化测试经验,能够使用 Python + Selenium + Pytest 框架编写UI自动化脚本,以及使用 Python + Requests 库进行接口自动化测试。
- 技术栈:我熟悉 MySQL 数据库进行数据校验,能够在 Linux 环境下查看日志、监控服务状态,并使用 Git/SVN 进行版本控制。
我是一个注重细节、有责任心且乐于沟通的人,能够积极地与开发和产品团队协作,共同推动项目高质量上线。上一份工作让我积累了扎实的测试功底,我希望能在新的平台接受更大的挑战,与公司共同成长。
我大学学的是计算机相关专业,在校期间就接触了《软件工程》和《软件测试》等课程,对保证软件质量的重要性有了初步的认识。毕业后,我认为软件测试是一个既需要技术能力,又需要业务理解和细致耐心的岗位,这种综合性的挑战非常吸引我。它作为产品上线前的最后一道防线,让我觉得非常有成就感,所以我选择从软件测试作为我的职业起点,并一直坚持到现在。
虽然我对编程有兴趣并且具备一定的编码能力,但在职业选择上,我发现自己更倾向于从用户的角度、从整体的视角去审视和保障一个产品的质量。相比于实现单一功能的开发工作,我更享受设计测试用例、模拟各种用户场景、发现潜在问题的过程。我喜欢这种“破坏性”的创造,通过发现问题来帮助产品变得更好,这种成就感对我来说比单纯的编码实现要更大。
主要有三个原因:
- 价值感:软件测试是保证产品质量的关键环节,直接关系到用户体验和公司的口碑。能够通过我的工作,为用户提供一个稳定、可靠的产品,让我觉得非常有价值。
- 综合性:这个岗位不仅要求技术能力,比如写脚本、操作数据库和服务器,还非常考验业务理解能力、逻辑思维能力和沟通能力。我喜欢这种多元化的挑战。
- 发展前景:随着行业发展,用户对软件质量的要求越来越高,测试行业也在不断进步,从传统的手工测试到自动化、性能、安全测试等领域,有广阔的学习和发展空间,这让我对未来充满期待。
我喜欢测试岗位,因为它让我能够站在产品质量守护者的角度,去全面地、批判性地思考问题。每当通过精心的用例设计发现一个隐藏很深的缺陷,或者在一个复杂的业务流程中定位到问题的根源时,我都会获得巨大的满足感和成就感。同时,这个岗位也促使我不断学习新的业务知识和测试技术,与团队成员紧密沟通协作,这种持续成长和团队合作的感觉也让我非常享受。
我认为软件测试是软件生命周期中不可或缺的核心环节,它的重要性正在被越来越多的公司所认可。
- 从过去看:测试可能被认为是开发流程的附属,技术含量不高。
- 从现在看:它已经发展成为一个专业领域,涵盖了功能、性能、安全、自动化等多个方向,对从业者的综合能力要求越来越高。
- 从未来看:随着AI、大数据等技术的发展,测试将变得更加智能化和精细化,比如探索性测试、精准测试等。我认为这个行业充满了机遇和挑战,是一个值得长期深耕的领域。
我认为测试的核心价值在于风险控制和质量保障。具体体现在三个方面:
- 发现缺陷:这是最直观的价值,通过在产品上线前尽可能多地发现并推动修复缺陷,降低线上故障的风险。
- 建立信心:通过系统全面的测试,为产品经理、开发团队、管理层乃至最终用户建立产品质量的信心,确保产品可以按时、高质量地发布。
- 预防缺陷:测试的价值不仅仅是“找Bug”,更重要的是通过参与需求和设计评审,提前发现逻辑漏洞和潜在问题,将质量控制的环节前移,从源头上减少缺陷的产生。
我认为一个优秀的测试工程师需要具备以下几个方面的专业素养:
- 扎实的测试理论基础:熟悉测试流程、方法(如等价类、边界值)和各种测试类型。
- 熟练的技术栈:掌握至少一门编程语言(如Python)、SQL、Linux常用命令,以及常用的测试工具(如Jira、Postman、JMeter、Selenium)。
- 深刻的业务理解能力:能够快速学习和理解业务需求,站在用户的角度思考问题。
- 优秀的软技能:
- 沟通能力:清晰、准确地描述问题,能与产品、开发有效沟通。
- 细心和耐心:能够发现不易察觉的细节问题,并耐心排查疑难杂症。
- 责任心:对自己负责的模块质量有强烈的责任感。
- 持续学习的能力:测试技术和工具更新换代快,需要不断学习提升自己。
-
优点:
- 责任心强,做事严谨:我对经手的测试任务会负责到底,力求交付高质量的工作成果。在设计用例时会力求覆盖全面,提交的Bug描述清晰、步骤明确,便于开发定位。
- 逻辑思维能力好,善于分析问题:在测试中遇到问题时,我习惯于先分析日志、检查数据库,进行初步定位,判断是前端问题、后端问题还是数据问题,这能提高与开发沟通的效率。
- 学习能力和适应性强:我乐于接触新技术和新业务,能够通过查阅资料和请教同事,快速上手并投入工作。
-
缺点: 在某些技术领域,比如性能测试调优方面,我的经验还主要停留在执行和分析报告的层面,对于更深层次的瓶颈定位和调优实践还不够深入。但我已经意识到了这一点,并计划在未来通过系统学习和项目实践来加强这方面的能力。
我目前最擅长的是基于复杂业务的功能测试。尤其是在电商领域,我对订单处理、库存管理、优惠促销等核心模块的业务逻辑有比较深入的理解。我擅长将复杂的业务需求拆解成清晰的测试点,并运用等价类、边界值、场景法等设计出覆盖度高且易于执行的测试用例,能够高效地保障这些核心功能的质量。
经过三年的积累,我最擅长的是功能测试和接口测试。
- 在功能测试方面,我已经形成了自己的一套完整的工作方法,能够独立负责一个复杂模块的测试,确保其按时高质量交付。
- 在接口测试方面,我不仅能用工具测试单个接口,还能设计接口测试用例,覆盖正常的业务流程和各种异常场景,保障后端服务的稳定性和可靠性。
我之所以认为自己擅长功能测试,主要基于以下三点:
- 系统的方法论:我不仅仅是凭感觉去点点点,而是严格依据需求,运用等价类、边界值、场景法、错误推测等多种测试设计方法,来保证用例的系统性和覆盖度。
- 深入的业务理解:在电商项目中,我不仅了解“做什么”,还喜欢探究“为什么这么做”。例如,在测试优惠券时,我会深入理解不同优惠券(如满减、折扣、品类券)的叠加规则和互斥逻辑,从而设计出更具挑战性的测试场景。
- 高效的缺陷定位能力:我能够熟练使用浏览器开发者工具、查看服务器日志、查询数据库,快速定位问题是前端、后端还是数据问题,从而提高缺陷流转的效率。
我离开上一家公司的主要原因是寻求更好的职业发展空间。在之前的公司我已经工作了三年,非常感谢公司对我的培养,我也从一个新人成长为能够独立负责模块的测试工程师。但目前公司的业务和技术栈趋于稳定,我个人在自动化测试和性能测试方面有很强的提升意愿,希望能够加入一个技术氛围更浓厚、业务发展更迅速的团队,接触更复杂的挑战,从而在专业技能上获得更快的成长。
我离职大概[根据实际情况回答,例如:一周/两周]了。在办理完离职交接后,我花了一点时间来复盘和总结过去三年的工作经验,并明确了自己下一阶段的职业目标,然后开始看新的机会。
(如果离职时间较长) 离职后我处理了一些家里的事情/[给自己放了一个短暂的假期来调整状态]。现在事情已经处理完毕/[调整好了],我希望能够尽快投入到新的工作中,所以最近开始积极地寻找合适的机会。
我现在就在[你所在的城市,例如:广州]。
我目前是离职状态,可以随时到岗。
我刚开始找工作,大概[根据实际情况回答,例如:一周]左右。
目前有几家公司在流程中,也收到了一个口头offer,但我对贵公司的岗位更感兴趣,觉得与我的职业规划和技术背景更加匹配,所以希望能有机会加入贵公司。
(如果之前以此为理由) 是的,已经全部处理妥当了,现在可以完全专注于工作。
如果面试顺利,我可以在收到正式offer后的一周内办理入职手续。
我认为需要客观看待这个问题。一方面,适度的跳槽可以让个人接触不同的业务和技术,快速成长;但另一方面,过于频繁的跳槽不利于个人在特定领域的深度积累,也对公司的稳定性和项目延续性有影响。我个人倾向于在一个有发展前景的平台上稳定工作,深入理解业务,与公司共同成长。我过去的三年都在同一家公司,也证明了我是一个相对稳定的人。
首先,我会保持冷静,不会轻易否定自己。
- 主动分析原因:我会全面复盘,分析是哪方面导致了“胜任不了”的感觉。是业务知识不熟悉?是技术能力有差距?还是工作方法或沟通上存在问题?
- 积极寻求帮助:我会主动向我的直属领导请教,坦诚地沟通我遇到的困难,寻求他的指导和建议。同时,我也会向身边的资深同事学习,了解他们是如何处理类似工作的。
- 制定提升计划:针对分析出的短板,我会制定一个明确的学习和提升计划。如果是业务不熟,就加班加点熟悉需求文档和系统;如果是技术不行,就利用业余时间系统地学习和练习。
- 定期复盘:我会定期审视自己的进步,确保自己正走在正确的轨道上。
我相信,通过主观的努力和积极的沟通,绝大多数问题都是可以被克服的。
我认为外包公司和自研公司各有特点。外包公司可以让人在短时间内接触到不同行业、不同类型的项目,快速拓宽技术和业务视野。自研公司则能让人更深入地钻研某一领域的业务,对产品的整个生命周期有更强的参与感和归属感。两者没有绝对的好坏,关键在于是否符合个人在特定阶段的职业发展需求。
我主要还是看项目本身和我在团队中扮演的角色。如果项目有挑战性,能让我学到新的技术或深入复杂的业务,并且团队的技术氛围好,那么我不会排斥外包的形式。我更关心的是工作内容本身能否给我带来成长。
同上,可以接受。我关注的是岗位本身的发展和锻炼机会。
我希望进入一家产品有前景、技术有追求、团队有活力的公司。具体来说:
- 产品有前景:公司的业务处于上升期,这样我能接触到不断迭代的新需求和新挑战。
- 技术有追求:公司重视技术和质量,愿意投入资源去改进研发和测试流程,鼓励技术创新。
- 团队有活力:团队成员之间能够开放沟通、互相学习、共同进步,有一个积极向上的工作氛围。
答案同上。
答案同上。
我之前的经验主要集中在B2C电商领域,未来我希望能在两个方向上拓展:
- 更复杂的电商业务:比如B2B领域、跨境电商或者带有供应链、金融属性的电商项目,这能让我的业务理解能力更加深入。
- 其他领域:比如金融、在线教育或者企业服务(SaaS)类的项目,我也很感兴趣,希望通过接触不同领域的项目来拓宽我的知识面。
我之前的公司是自研产品的公司。
我的职业规划分为短期和长期两个阶段:
- 短期规划(1-3年):我希望能够在新公司尽快熟悉业务和团队,扎实地完成本职工作。在此基础上,我计划在自动化测试和性能测试方面进行系统性的学习和实践,争取能够独立负责项目的自动化测试框架搭建或性能瓶颈分析,成为一名优秀的资深测试工程师。
- 长期规划(3-5年):我希望能够成长为一名测试专家或测试管理者。在技术路线上,我希望能成为某个测试领域(如性能或安全)的专家;在管理路线上,我希望能带领一个小团队,负责整个项目的测试策略和质量保障。我会根据公司的发展和自己的兴趣来选择最终的方向。
我的学习规划主要围绕三个方面:
- 深度:深入学习自动化测试技术,比如研究 Pytest 框架的更高级用法,学习接口自动化的持续集成。同时,系统学习性能测试,从脚本录制、场景设计到监控分析、瓶颈定位,形成完整的知识体系。
- 广度:拓宽知识面,学习一些与测试相关的开发知识,比如前端的JS或者后端的微服务架构,这能帮助我更好地理解系统,定位问题。
- 实践:理论结合实践,在业余时间自己搭建项目进行练习,或者积极争取在公司项目中应用所学的新技术。
短期内,我想继续在技术路线上深耕,目标是成为一名资深的自动化测试或性能测试工程师。我享受技术带来的挑战和解决问题的成就感。
是的,这是我非常明确的目标之一。我认为自动化是提升测试效率和保障回归质量的关键手段,也是测试工程师技术能力的重要体现。我希望通过不断的学习和实践,在这个方向上有所建树。
我并不是只找纯自动化的岗位。我理解对于大多数公司来说,业务功能测试仍然是基础和核心。我希望找到一个功能测试为主,同时有机会让我实践和发展自动化测试的岗位。这样既能发挥我现有的优势,又能满足我学习和成长的需求,实现一个平稳的过渡和提升。
非常考虑。功能测试是我的强项,也是我理解业务、发现有价值缺陷的主要方式。我完全可以胜任功能测试的工作。同时,我也相信随着业务的发展和稳定,公司肯定会考虑引入自动化来提升效率,我希望届时能有机会参与其中,贡献我的力量。
有考虑过。我认为技术和管理是相辅相成的。在未来,当我的技术能力和项目经验积累到一定程度,对业务和团队有了足够深入的了解后,如果公司有需要,我愿意尝试承担一些管理职责,比如带领新人、协调项目资源、把控测试进度等。
在正式的管理岗位上我还没有经验,但在之前的项目中,我承担过类似“小组长”的角色。比如在一个大的模块中,我会负责将测试任务拆解给新同事,并对他们的测试结果进行复核,在他们遇到问题时提供指导。
我目前主要通过观察我的前领导是如何管理团队、规划项目和沟通协调的,从中学习经验。另外,我也阅读过一些关于项目管理和团队协作的书籍,比如《人月神话》等,对管理有了一些理论上的认识。
带过。公司之前有新同事入职,领导会安排我来带,主要是在业务和工作流程上进行指导。
两者都有。
- 业务方面:我会给他讲解我们负责的业务模块的流程、核心逻辑以及历史遗留的一些“坑”。
- 技术方面:我会教他如何使用公司的测试工具、如何搭建测试环境、如何规范地提交Bug等。如果他遇到一些技术难题,我也会尽我所能帮助他一起解决。
现阶段,我最想提升的是自动化测试和性能测试的实战能力。我希望不仅仅是停留在“会用”的阶段,而是能做到“用好、用精”,比如能够独立设计和搭建一个小型项目的自动化测试框架,或者能够独立完成一次性能测试并给出初步的分析报告。
主要就是自动化测试和性能测试这两个方向。这是当前测试领域最重要的两个技术分支,也是衡量一个测试工程师技术水平的重要标准。
结合我三年的工作经验、掌握的技能以及上海的市场行情,我期望的薪资范围是 [给出一个合理的范围,例如:12k-15k]。当然,我相信贵公司有完善的薪酬体系,最终可以根据我的面试表现和岗位职级来综合评定。
我希望能达到我期望范围的下限,也就是[例如:12k],因为这个数字是我综合考虑了我的能力价值和生活成本后得出的。但我更看重的是公司的发展平台和岗位的成长空间,如果机会非常好,薪资方面我们也可以再商量。
我上一家公司的薪资构成是[例如:月薪 + 季度奖金 + 年终奖],综合下来月薪大概在 [例如:10k] 左右。
是按照国家规定的标准正常缴纳的,五险一金都有。公积金是按照[例如:12%]的比例缴纳的。
我们公司平时加班不多,工作效率比较高。主要是在项目迭代的关键时期,比如临近上线或者有紧急需求时,大家会一起加加班,确保项目能顺利发布。
不严重,属于正常的行业加班情况,有张有弛。
大概一个月会有那么一两周,在版本发布前会加班到晚上八九点。周末加班的情况非常少,除非是线上有紧急故障需要处理。
我认为加班是现代互联网工作中难以完全避免的现象,对此我有两点看法:
- 效率优先:我首先会努力在工作时间内高效地完成任务,尽量避免因为个人效率问题导致的加班。
- 接受必要加班:如果是项目需要,比如为了赶版本发布、处理紧急的线上问题,我完全理解并接受必要的加班,这是团队责任感的体现。但我不太赞成无意义的、常态化的“内卷式”加班。
我能接受为了项目目标的、阶段性的加班。比如项目冲刺阶段的“995”是可以接受的,但我不希望这成为一种常态。我更追求工作和生活的平衡,这样才能保持长期的工作热情和创造力。
如果是短期的、项目非常紧急的情况下,我可以接受。但如果996是公司的常态化制度,我可能需要慎重考虑,因为它会影响我的学习充电时间和个人生活,长期来看不利于个人和公司的共同发展。
我希望单程通勤时间能控制在一个小时以内,这样可以保证我有充足的精力和时间投入到工作和学习中。
我大学读的是[例如:计算机网络与技术]专业。
我们专业开设了《数据库》、《计算机网络》、《Python》等课程,这些都为我从事软件测试工作打下了坚实的理论基础。
我们专业开设了《数据库》、《计算机网络》、《Python》等核心课程。
(此为示例,如非本专业则忽略) 我大学的专业是酒店管理,虽然没有直接的计算机课程,但这个专业培养了我很强的服务意识、沟通能力和注重细节的习惯。入行测试后,我发现这些软技能对我理解用户需求、与人协作非常有帮助。计算机相关的技术都是我出于兴趣和职业发展需要,通过在线课程和自学系统学习的。
是的,我的学历是国家承认的本科学历,学信网可查,是全日制统招的。
主要通过三个途径:
- 大学课程:在校期间学习了Python的基础。
- 在线学习:工作后,为了转向自动化测试,我系统地学习了Python的一些框架,主要是在B站和一些付费课程平台上学习,跟着老师的视频敲代码、做项目。
- 工作实践:在实际工作中编写自动化脚本是最好的学习方式,遇到问题就查资料、问同事,在解决问题的过程中能力提升最快。
大学时期就接触了,打下了一些基础。入行后,为了工作需要,更有针对性地进行了深入学习和实践。
我的英语读写能力还可以,能够顺利阅读英文的技术文档和资料。听说能力一般,可以进行简单的日常交流。
是的,大学期间已经通过了英语四级。
有非常丰富的自学经历。可以说,我工作后的大部分技能,比如Python编程、JMeter、Selenium、Linux等,主要都是通过自学掌握的。我习惯于为自己设定学习目标,然后通过看书、看视频、写代码实践的方式来达成。我认为自学能力是IT从业者一项非常重要的核心能力。
我认为我的适应能力很强。每进入一个新的项目,我都能通过主动阅读需求文档、请教产品和开发同事、自己动手操作熟悉系统这几个方式,快速了解业务逻辑和技术架构,通常在一到两周内就能上手承担测试任务。
我通常需要一到两周的时间来熟悉公司的流程、产品业务和团队成员。一个月左右,我就能完全融入团队,独立高效地开展工作。
我会从三个方面入手:
- 宏观了解(看文档):首先通读项目相关的文档,如需求文档、产品原型、接口文档等,对项目整体的业务流程和功能模块有一个大致的了解。
- 微观体验(动手操作):自己在测试环境上把系统的主要功能流程都操作一遍,像一个真实用户一样去使用它,加深对业务的理解。
- 积极沟通(多问):对于不理解的业务逻辑或技术细节,我会整理好问题,主动找相关的产品、开发或老同事请教,这是最高效的方式。
我会遵循“明确目标 -> 拆解任务 -> 学习研究 -> 制定计划 -> 执行反馈”的步骤:
- 明确目标:首先和领导充分沟通,确保我完全理解这个任务的目标、要求和期望的产出是什么。
- 拆解与学习:分析完成这个任务需要哪些知识和技能。对于我不会的,立刻去学习;对于我会的,将其拆解成一个个可执行的小步骤。
- 制定计划:制定一个详细的工作计划,包括每个步骤的时间节点和预期成果,并和领导确认。
- 执行与反馈:在执行过程中,小步快跑,遇到问题及时解决,并定期向领导汇报进度和遇到的困难,寻求支持。
同事们普遍认为我是一个乐于助人、沟通顺畅的合作伙伴。开发同事觉得我提的Bug质量高,定位准,便于他们修改。领导对我的评价是工作主动、责任心强,交给我的任务能按时按质完成,比较放心。
我们项目组的测试和开发比例大概是 1:4 左右。
我们遵循的是小步快跑的迭代模式,一个迭代周期通常是两周。
为了不影响用户白天的正常使用,我们的产品上线一般会选择在用户量最少的时间段,通常是周四凌晨1点到3点之间。
我遇到过的一个比较大的困难是,有一次项目版本迭代非常快,需求文档写得比较粗略,导致测试范围不明确。我的做法是:首先,主动组织了一个由产品、开发和我参加的短会,在会上把所有不明确的点都过了一遍,明确了需求细节和验收标准。然后,我用思维导图快速梳理出测试要点,并再次和产品、开发确认,确保大家理解一致。通过这种方式,虽然前期多花了一些沟通成本,但有效避免了后期因为理解偏差导致的返工,保证了测试的覆盖率。
(同上,可以准备一到两个案例,一个偏向流程沟通,一个偏向技术难题) 技术上的一个难题是,曾经遇到过一个偶现的Bug,只在特定操作序列下以很低的概率出现。为了复现和定位它,我花了大量时间反复尝试,并最终通过分析服务器日志,发现是由于某个服务在处理高并发请求时,一个非线程安全的变量被意外修改导致的。这个过程虽然艰难,但成功定位后非常有成就感。
我的主要职责包括:
- 需求阶段:参与需求评审,理解需求并从测试角度提出疑问和建议。
- 计划阶段:评估测试范围和工作量,协助测试组长制定测试计划。
- 设计阶段:根据需求设计测试用例,编写用例并参与用例评审。
- 执行阶段:搭建和维护测试环境,执行测试用例,提交和跟踪缺陷,直到缺陷被修复并验证通过。
- 回归阶段:执行回归测试,确保新功能没有影响到老功能。
- 上线后:跟进线上版本,进行线上验证,并协助排查线上问题。
遇到过。印象最深的一次是,一个重要版本临近上线日期,但开发提测时间比原计划晚了两天,导致我们的测试时间被严重压缩。当时压力非常大。
我的应对方式是:
- 评估风险:第一时间评估了剩余时间内的测试风险,识别出核心功能和高风险模块。
- 调整策略:我向领导汇报了情况,并提出调整测试策略的建议:优先保证核心功能的测试,对于次要功能和边缘场景,暂时降低测试优先级。同时,我们进行了一轮高效的冒烟测试,确保主流程没有阻塞性问题。
- 加强沟通:我和对接的开发同学保持非常紧密的沟通,一旦发现阻塞性或严重的Bug,立刻找到他,争取第一时间修复,减少等待时间。
- 团队协作:团队内部也进行了分工,大家一起加班,最终在保证核心质量的前提下,按时完成了测试任务。
我会把压力看作是成长的一部分,并积极地去应对它。
- 分析压力来源:首先搞清楚压力的来源,是任务重、时间紧,还是能力不足、对业务不熟悉。
- 拆解和求助:如果是任务重,我会对任务进行拆解和优先级排序。如果是能力或业务问题,我会主动向领导和同事请教,快速学习。
- 调整心态:保持积极的心态,相信自己有能力克服困难。
- 劳逸结合:工作之余,通过运动、听音乐等方式放松自己,保持良好的身心状态。
刚进入新公司,可能会在以下方面感到压力:
- 业务熟悉:需要快速学习和理解全新的业务模式和逻辑。
- 团队磨合:需要尽快适应新的团队文化、沟通方式和工作流程。
- 技术挑战:可能会遇到自己不熟悉的技术栈或工具。 但我有信心通过自己的努力和主动沟通,在短时间内克服这些压力。
- 工作内:我会把大的压力源分解成一个个小任务,每完成一个就给自己一个正向反馈。同时,找同事或领导聊一聊,倾诉一下,通常能得到很好的建议和支持。
- 工作外:我会通过运动来解压,比如跑步或打球,让身体出汗,精神会放松很多。或者听听音乐、看看电影,暂时从工作中抽离出来,转换一下心情。
我认为核心是尊重、真诚和双赢。
- 主动沟通:无论是工作协作还是日常交流,都保持积极主动。
- 乐于助人:在自己力所能及的范围内,多帮助同事,建立良好的关系。
- 专业对事:讨论工作时,对事不对人,基于事实和数据说话,即使有分歧也要尊重对方。
- 换位思考:多站在对方的角度想问题,尤其是在和开发沟通Bug时,理解他们的工作压力和思维方式。
有发生过意见不一致的情况,但算不上激烈的冲突。最常见的原因是对一个Bug的严重级别或是否是Bug本身有分歧。 比如,我提了一个UI上的显示问题,我认为这会影响用户体验,应该修复。但开发同学认为这只是个小问题,优先级不高,当前版本可以不修。
我的处理方式是:
- 阐明我的观点:我会从用户的角度出发,向他解释为什么我认为这个问题很重要,可能会给用户带来什么样的困扰,或者对产品形象有什么样的影响。
- 寻求第三方意见:如果开发仍然坚持,我们会把这个问题上升到产品经理那里,由产品经理来最终决定这个问题的优先级和解决方案。 通过这种方式,我们把对问题的分歧转化为一个共同寻求最优解的过程,而不是个人之间的争执。
(此类问题答案因人而异,以下提供回答思路)
支持的。他们知道北京有更好的发展机会和平台,虽然会有些不舍,但还是鼓励我出来闯一闯,追求自己的事业发展。
我之前在[例如:郑州]工作。
选择来[例如:北京],主要是因为这里是互联网行业的中心,有更多的优秀公司和工作机会,技术氛围也更浓厚。我希望在这个环境里,能更快地提升自己,接触到更前沿的技术和更复杂的项目。
(根据实际情况回答) 是的,目前是单身。/ 我有男朋友/女朋友了。
(根据实际情况回答) 偶尔会提一下,但还是比较尊重我自己的节奏和想法。
(根据实际情况回答,展示积极的生活态度) 缘分很重要,但我相信提升自己、扩大社交圈会更有帮助。现阶段我还是以事业为重,但也会积极地去认识新的朋友。
(HR关心稳定性问题,回答要professional) 我目前未婚,近两到三年还是会把重心放在事业发展上,希望能在工作上取得一定的成绩,暂时没有要小孩的计划。
(如实回答) 一致的。/ 不一致,因为[给出合理解释,如:当时上户口时报晚了等]。
我平时喜欢运动,比如跑步和爬山,这能帮助我保持精力和健康的状态。另外也喜欢看一些技术博客和书籍,算是工作相关的爱好吧,能让我保持学习的习惯。
(这是一个考察情商的问题) 我觉得和您的交流非常愉快,您提的问题都非常专业,而且很有深度,让我对自己过去的工作有了更深入的复盘和思考,我给你这次面试表现打95分吧。
我参与过的项目主要是一个大型的B2C电商平台,我称之为“优购商城”。这个项目包含了用户端(App和Web)、商家后台和平台运营后台。
我最近参与的“优购商城”项目,是一个综合性的B2C电商平台。
- 项目目标:为用户提供在线购物服务,涵盖商品浏览、搜索、购物车、下单、支付、订单管理、售后等全链路功能。
- 技术架构:项目采用微服务架构,前端是Vue框架,App是原生开发,后端主要是Java。
- 我的角色:在项目中担任测试工程师,主要负责订单中心和营销活动(如优惠券、秒杀)这两个核心模块的测试工作。
这个项目同时包含了 Web 端和 App 端,两者共用一套后端服务。我参与了两个端的测试,但主要精力更多地投入在 App 端的测试上,因为我们公司的核心用户群体在移动端。
我的主要经验集中在电商项目。在公司内部,我也短暂地支持过一个内部使用的OA系统项目,主要负责了请假和审批流程的测试。
没有直接参与过完整的金融项目,但在电商项目中,我负责的支付模块会涉及到与第三方支付渠道(如微信支付、支付宝)以及公司内部账务系统的对接,对支付流程中的资金流向、对账、异常处理等有一定的了解。
是的,已经上线并且在稳定运营中。我们基本上保持着每两周一个迭代版本的更新频率。
我们App的版本号目前是 v3.5.2。
最近的v3.5版本我们主要上线了两个大功能:
- 直播购物功能:用户可以在主播的直播间里直接点击商品链接进行购买。
- 会员积分体系优化:重新设计了用户的成长值和积分获取、兑换规则,增加了积分商城。 我主要负责了直播购物流程中,从直播间到下单支付这个链路的测试。
具体的运营数据我不是非常清楚,但据我了解,我们App在各大应用市场的累计下载量已经超过了500万。
这个数据属于公司核心商业数据,我没有权限获取到精确的数字。但根据产品和运营同学的分享,我们App的日活跃用户数大概在10万这个量级。
初始化库存: 库存数据预加载 操作: 在抢购活动开始前,将商品的库存数据预先加载到Redis中。 实现: 使用Redis的 SET 命令将库存数量存储在Redis中 库存扣减: 乐观锁机制 操作: 在用户请求扣减库存时,使用Redis的 DECR 命令进行库存扣减,并检查扣减后的结果是否大于等于0。 实现: 如果扣减后的结果大于等于0,表示库存充足,用户可以继续购买。 如果扣减后的结果小于0,表示库存不足,用户不能购买,返回“库存不足”的提示。
“优购商城”项目主要包含以下几个大模块:
- 用户中心模块(注册、登录、个人信息管理)
- 商品模块(商品详情、搜索、分类)
- 购物车模块
- 订单中心模块(下单、订单列表、订单详情)
- 支付模块
- 营销活动模块(优惠券、秒杀、拼团)
- 售后模块(退款、退货)
有涉及到。主要是平台运营后台和商家后台。
- 平台运营后台:我主要用它来配置测试数据,比如创建营销活动、配置优惠券、手动修改订单状态等。
- 商家后台:我也会测试商家入驻、商品上架、订单处理等相关功能。
不是的,我们测试团队有4个人,进行了模块划分。我主要负责的是订单中心模块和营销活动模块。
我主要负责的是订单中心模块和营销活动模块。
是的,我们4个测试工程师共同负责。我的职责范围是订单中心和营销活动。
- 订单中心:包括从购物车或商品详情页发起下单,到填写收货地址、选择优惠、确认订单、调用支付、查看订单状态流转的整个正向流程,以及取消订单、申请售后的逆向流程。
- 营销活动:包括优惠券的创建、发放、用户领取和使用,以及秒杀活动的商品提报、活动配置和前端展示、下单限制等。
好的,我以下单流程这个核心业务逻辑为例:
- 触发下单:用户在购物车勾选商品,点击“去结算”,或者在商品详情页点击“立即购买”。
- 订单确认页:系统进入订单确认页面。后端服务会进行一系列校验:
- 用户校验:检查用户登录状态。
- 商品校验:检查商品是否存在、是否上架、库存是否充足。
- 价格计算:获取商品的最新价格,并计算商品总额。
- 优惠计算:拉取用户可用的优惠券、红包等信息,并计算出最优的优惠组合。
- 用户提交订单:用户确认收货地址、商品信息、优惠和金额无误后,点击“提交订单”。
- 创建订单:
- 风控校验:后端会对本次下单行为进行风险评估,比如判断是否为黄牛刷单。
- 库存预占:调用库存服务,对订单中的商品进行库存预扣减。如果扣减失败,则下单失败。
- 订单生成:在订单库中生成一条主订单和若干子订单记录,状态为“待支付”。
- 优惠核销:如果使用了优惠券,会调用营销服务,将优惠券状态置为“已使用”。
- 拉起支付:返回订单号和支付所需信息给前端,前端拉起支付渠道(如微信、支付宝)的SDK,用户进行支付。
- 支付结果回调:用户支付成功后,支付渠道会异步回调我们的支付服务。支付服务在确认收款后,会发送消息通知订单服务。
- 更新订单状态:订单服务收到支付成功的消息后,将订单状态更新为“待发货”,并通知库存服务进行库存的真实扣减。同时,可能会触发给用户发送通知、给仓库系统推送发货单等下游操作。
这个流程涉及到用户、商品、库存、营销、订单、支付等多个微服务之间的协作,是整个电商链路的核心。
电商项目的核心业务流程可以概括为信息流、资金流、物流三条主线。
- 信息流:用户从浏览商品、搜索、加入购物车,到提交订单、查看订单状态,商家从上架商品、处理订单到发货,平台从管理商品、用户到监控订单,这整个过程都是信息流。
- 资金流:用户下单后,通过第三方支付或平台余额进行支付,款项先到平台,平台与商家结算后,再将款项打给商家,以及处理用户退款,这整个过程是资金流。
- 物流:商家接到订单后,从仓库打包、发货,通过物流公司运输,到用户最终签收,以及逆向的退货流程,这整个过程是物流。 我的测试工作就是围绕这三条主线,确保它们在系统中的各个环节都能正确、高效地流转。
- 加购:用户在商品列表页或详情页,选择规格(如颜色、尺码)和数量,点击“加入购物车”。系统会判断购物车中是否已存在相同商品,如果存在则增加数量,不存在则新增一条记录。
- 查看:用户进入购物车页面,可以看到已加购的商品列表,包括商品图片、标题、规格、单价、数量等。
- 修改:用户可以修改商品的数量(增加、减少、手动输入),或者删除单个/多个商品。
- 管理:用户可以对失效商品(如下架、无货)进行清理。
- 结算:用户勾选需要购买的商品,点击“结算”,系统会带着这些商品信息跳转到订单确认页。
我会从功能、UI、性能、兼容性、安全性几个方面来设计测试点:
- 功能测试:
- 加购:
- 未登录/已登录状态下加购,商品能否成功添加。
- 不同入口(列表页、详情页、活动页)加购。
- 添加普通商品、秒杀商品、预售商品等不同类型商品。
- 添加商品时,数量、规格选择是否正确。
- 购物车商品数量是否有上限,达到上限后如何处理。
- 商品达到库存上限后,能否继续添加。
- 查看与管理:
- 购物车页面商品信息(图、文、价、规格、数量)显示是否正确。
- 修改商品数量,小计和总价是否实时更新。
- 删除单/多个/全部商品,功能是否正常。
- 全选/反选功能是否正常。
- 对失效商品(已下架、无库存)是否有明显标记,能否正常清理。
- 结算:
- 勾选单/多个商品结算,传递到订单确认页的数据是否正确。
- 未勾选任何商品时,结算按钮应置灰。
- 购物车数据同步:在Web端加购,App端能否看到,反之亦然。
- 加购:
- UI测试:页面布局、字体、颜色、按钮样式是否符合设计稿。
- 性能测试:快速、频繁地添加、删除商品,系统响应是否及时,后台服务有无异常。
- 兼容性测试:在不同浏览器、不同手机型号和操作系统版本上,购物车功能是否正常。
- 安全性测试:通过抓包修改请求参数(如商品ID、价格),看能否以错误的价格加购或结算。
- 功能测试:
- 必填项校验:用户名、密码、手机号等必填项为空时,应有相应提示。
- 格式校验:
- 手机号:输入非11位、非数字、错误的号段。
- 密码:长度、复杂度(数字、字母、特殊字符组合)是否符合要求。
- 验证码:输入为空、错误、过期的验证码。
- 唯一性校验:使用已注册的手机号进行注册,应提示“该手机号已被注册”。
- 流程测试:
- 获取验证码按钮:点击后是否倒计时,倒计时期间是否置灰,单位时间内是否限制获取次数。
- 注册成功:所有信息填写正确,点击注册,应提示成功并自动登录或跳转到登录页。
- 用户协议:不勾选用户协议,注册按钮是否置灰。
- 安全性测试:
- 密码是否密文传输。
- 短信验证码是否容易被爆破(如纯数字、有效期过长)。
- 是否存在SQL注入或XSS攻击风险。
- 兼容性和UI测试:在不同设备上,页面显示和功能是否正常。
与注册类似,主要覆盖功能、安全、性能、兼容性等方面:
- 功能测试:
- 登录方式:测试账号密码登录、手机验证码登录、第三方(微信、QQ)登录等多种方式。
- 正确性:输入正确的账号密码/验证码,能成功登录并跳转到指定页面。
- 异常场景:
- 账号或密码错误、为空。
- 账号不存在、被冻结。
- 验证码错误、过期。
- 多次输错密码,账号是否会被锁定,锁定后如何解锁。
- 记住密码/自动登录:勾选后,关闭浏览器/App再打开,是否能保持登录状态。
- 注销:退出登录后,能否返回登录页,并且不能再访问需要登录的页面。
- 安全性测试:
- 密码是否加密传输。
- 是否存在暴力破解风险(有无验证码、登录失败次数限制)。
- 测试 Session/Token 管理机制,退出登录后,之前的Token是否失效。
- 是否存在越权风险,比如用A用户的Cookie/Token能否访问B用户的信息。
- 性能和兼容性测试。
抢购模块测试的核心是并发和数据一致性。
- 前端测试:
- 活动开始前:抢购按钮置灰,显示倒计时。
- 活动进行中:按钮变为可点击状态。
- 活动结束后/库存抢完后:按钮置灰,显示“已结束”或“已抢光”。
- 后端功能测试:
- 库存控制:是核心中的核心。保证“超卖”问题不会发生。可以通过JMeter等工具模拟大量并发请求,验证最终成功下单的数量是否严格等于库存数量。
- 时间控制:在活动开始时间点之前和结束时间点之后,都不能下单成功。需要特别注意服务器时间与客户端时间的差异。
- 购买限制:比如每个用户限购1件,要测试用户下第一单成功,下第二单失败的场景。
- 下单流程:抢购成功的用户,后续的支付、订单生成流程是否正常。
- 失败流程:抢购失败的用户,应有明确的提示(如“已抢光”、“活动未开始”)。
- 性能测试:
- 对抢购接口进行压力测试,观察在高并发下,系统的TPS每日交易量、响应时间和成功率,确保系统不会崩溃。
- 异常场景:
- 网络延迟或中断时,用户的抢购请求如何处理。
- 用户使用脚本或外挂进行抢购,系统有无风控机制。
- 优惠券的生命周期:
- 创建:在后台创建不同类型的优惠券(满减券、折扣券、无门槛券、品类券、商品券),配置是否正确。
- 发放与领取:测试手动发放、用户主动领取、注册赠送、消费返券等多种发放方式。测试领取渠道、数量限制、时间限制。
- 使用:
- 门槛校验:订单金额是否满足使用门槛。
- 范围校验:是否适用于指定的商品或品类。
- 时间校验:是否在有效期内使用。
- 互斥规则:多张优惠券或优惠券与其他活动(如秒杀、满减)能否叠加使用,规则是否正确。
- 过期与失效:测试优惠券到期后是否自动变为“已过期”状态,使用后是否变为“已使用”状态,订单取消后优惠券是否返还。
- 功能交互:
- 在订单确认页,系统是否能自动推荐最优的优惠券。
- 用户手动选择/取消优惠券后,订单金额是否正确重新计算。
- 数据一致性:
- 前端显示的优惠金额与后端实际计算的是否一致。
- 订单中使用优惠券后,订单详情、账务系统中的记录是否正确。
这是对场景法应用的考察,核心是组合测试和业务流测试。
- 优惠券与商品组合:
- 使用品类券购买指定品类的商品(成功)和非指定品类的商品(失败)。
- 使用商品券购买指定商品(成功)和非指定商品(失败)。
- 优惠券与订单金额组合:
- 订单金额刚好满足/略高于/略低于满减门槛。
- 凑单后满足门槛,取消部分商品后又不满足门槛。
- 多张优惠券叠加测试:
- 测试平台设置的叠加规则,比如品类券和平台通用券能否一起用。
- 优惠券与其它营销活动组合:
- 秒杀商品能否使用优惠券。
- 满减活动和优惠券能否同时享受。
- 优惠券与用户身份组合:
- 新人专享券,老用户是否能领取和使用。
- VIP会员券,普通用户是否能用。
- 正向/逆向流程组合:
- 使用优惠券的订单,发生部分退款/全部退款时,优惠券是否退回,退款金额计算是否正确。
- 功能测试:
- 红包类型:普通红包、拼手气红包。
- 发送:
- 输入金额(边界值:0.01,200,超过200)、个数。
- 支付密码/指纹验证。
- 发送给个人/群聊。
- 领取:
- 自己能否领取自己发的红包。
- 别人能否正常领取。
- 红包被领完后,其他人点击应提示“已领完”。
- 拼手气红包,所有人领取的总金额是否等于红包总额。
- 退款:24小时内未被领完的红包,金额是否会自动退回到发送者的零钱。
- 性能测试:
- 春节等高峰期,大量用户同时发/抢红包,系统的响应速度和稳定性。
- UI测试:
- 红包封面、领取页面的显示。
- 异常场景:
- 网络中断时,发送/领取红包如何处理。
- 账户余额不足时,发送红包应失败。
- 红包金额和个数的非法输入(负数、0、小数、超大数)。
- 发朋友圈:
- 内容:纯文字、图片(1-9张)、视频、链接分享、地理位置。
- 权限:公开、私密、部分可见、不给谁看。
- 交互:发布、编辑、删除。
- 点赞/评论:
- 功能:点赞、取消点赞;评论、回复评论、删除自己的评论。
- 通知:点赞/评论后,发布者是否能收到红点提醒。
- 权限:非好友能否点赞/评论(取决于对方设置),共同好友的可见性规则。
- 兼容性:不同手机、不同微信版本下的显示和功能。
- 性能:快速刷新、滚动朋友圈,图片和视频加载速度。
- 点赞:
- 功能:单击点赞(变红)、双击点赞(屏幕出心形动画),再次点击取消点赞。
- 数据一致性:点赞后,点赞数是否实时+1,刷新后是否保持。
- 性能:快速连续点击,前端动画是否卡顿,后端计数是否准确。
- 直播:
- 主播端:开播、美颜、滤镜、添加商品、发红包、禁言、下播。
- 观众端:进入/退出直播间、清晰度切换(流畅/高清)、弹幕、点赞、送礼物、购买商品、分享直播间。
- 性能:直播的流畅度、延迟、音画同步。在不同网络环境下(WiFi, 4G, 5G)的观看体验。
- 兼容性:不同手机型号的兼容性,特别是小窗播放、后台播放等功能。
库存是电商测试的重中之重,我主要关注以下几个点:
- 库存扣减时机:是下单时预占库存,还是支付成功后才真实扣减。我们项目是下单预占,支付成功后实扣。
- 库存数据一致性:
- 前端显示:商品详情页的库存数量是否和后台真实库存一致。
- 后端扣减:高并发下,库存扣减是否准确,绝不能出现超卖。
- 库存返还场景:
- 用户下单后,在规定时间内未支付,订单自动取消,预占的库存是否返还。
- 用户支付前,手动取消订单,库存是否返还。
- 用户支付后,申请退款/退货,审核通过后,库存是否返还。
- 多渠道库存同步:如果一个商品同时在App、Web、小程序等多个渠道销售,库存是否能实时同步。
- 库存与SKU存货单位关联:一件商品有多种规格(如衣服的S/M/L码),每个SKU的库存是独立的,测试时要确保操作A规格的库存,不影响B规格。
这是一个很好的场景题,考察的是对异常流程和数据一致性的理解。我们公司的处理逻辑是:
- 原则:以保障已下单用户的权益为优先。
- 逻辑:
- 下单即锁定:用户的下单行为,在系统层面已经完成了对库存的预占。这个预占的库存,是和商品的可售库存隔离的。
- 下架操作:商家执行“下架”操作,影响的是可售库存。系统会将商品的可售库存清零,使其在前台不可见、不可被搜索、不可再被下单。但这个操作不应该影响到已经被预占的库存。
- 完成支付:用户在下架后完成支付,由于库存已被预占,支付流程可以正常往下走。支付成功后,系统会进行真实扣减(即将预占库存变为已售库存),然后正常流转到待发货状态。
- 结论:商家可以正常看到这个订单并进行发货。这种逻辑保证了只要用户成功生成了待支付订单,就相当于拿到了一个购买凭证,后续商家的操作不应影响用户的支付和履约。
对于实物,可以从用户需求和产品属性出发进行测试。
- 功能测试:
- 装水:是否漏水(核心功能)。能装多少水(容量)。
- 插花:瓶口大小是否合适插不同数量和粗细的花枝。稳定性如何,插上花后是否容易倾倒。
- 清洁:瓶身内外是否容易清洗。
- 可靠性/耐用性测试:
- 从一定高度跌落,是否容易破碎。
- 长时间装水,材质是否会变色或被腐蚀。
- 易用性测试:
- 搬动是否方便,有无易于抓握的设计。
- 外观设计是否美观,是否符合宣传图片。
- 安全性测试:
- 材质是否环保无毒。
- 边缘是否光滑,有无割手的风险。
- 包装测试:
- 包装是否能有效保护花瓶在运输中不被损坏。
- 核心功能(保温性):
- 在特定室温下,装满95℃的热水,6小时/12小时后,水温分别是多少,是否达到宣传标准。
- 保冷性测试同理。
- 密封性:装满水后,倒置或摇晃,是否漏水。
- 易用性:
- 杯盖是否容易拧开和拧紧。
- 喝水是否方便,是否烫嘴。
- 是否容易清洗,有无死角。
- 安全性:
- 内胆和杯盖材质是否为食品级(如304不锈钢)。
- 盛放热水时,杯身外壁是否烫手。
- 可靠性:
- 抗摔性如何。
- 长期使用后,保温性能是否下降。
- 功能测试:
- 开关功能。
- 风速调节(低、中、高档)是否有效。
- 摇头功能是否正常,角度是否符合说明。
- 定时功能是否准确。
- 遥控器各项功能是否灵敏。
- 性能测试:
- 风量大小,送风距离。
- 噪音大小,在各档风速下是否在可接受范围内。
- 能耗,是否符合节能标准。
- 安全性测试:
- 防护网的缝隙是否足够小,能否防止儿童手指伸入。
- 运行是否平稳,底座是否稳固。
- 长时间运行后,电机是否会过热。
- 电线和插头是否符合安全标准。
- 可靠性测试:
- 连续运行24小时或更长时间,功能是否依然正常。
- 功能测试:
- 书写是否流畅,有无断墨、漏墨现象。
- 笔迹的颜色、粗细是否符合规格。
- 墨水干的速度快不快,是否容易蹭花。
- 可靠性/寿命测试:
- 一支笔能写多长的距离(在特定设备上划线直到写完)。
- 笔的耐摔性如何。
- 易用性测试:
- 握感是否舒适。
- 笔夹的夹力是否合适。
- 兼容性测试:
- 在不同类型的纸张上(A4纸、卡纸、餐巾纸)的书写效果。
这是一个考察思维发散性的问题,可以指物理日历或软件日历。以软件日历App为例:
- 功能测试:
- 数据显示:年月日、星期、节假日、农历、节气等信息显示是否准确。
- 时间准确性:闰年、大小月、跨年、跨时区的处理是否正确。
- 视图切换:年、月、周、日视图切换是否正常。
- 日程管理:新建、编辑、删除日程事件,设置提醒功能是否正常。
- UI测试:
- 界面布局是否美观、清晰。
- 性能测试:
- 快速翻页、切换视图是否流畅。
- 兼容性测试:
- 在不同分辨率、不同系统的手机上显示是否正常。
- 与其他App的交互,如从日历创建的日程能否同步到系统日历。
这是一个考察测试设计和估算能力的问题。
- 明确需求:首先要明确“使用时间”的定义,是指连续书写的总时长,还是能书写的总长度。通常“总长度”更具可操作性。
- 设计方案:
- 确定测试设备:为了保证测试的标准化和可重复性,不能用人来写。可以使用一个可以控制画图的机器臂,或者一个滚筒带动纸张、笔固定的设备。
- 确定标准:定义好书写的速度、压力、纸张类型。
- 执行测试:让机器以恒定的速度和压力在标准纸张上连续划线。
- 记录结果:记录从开始到墨水耗尽所划出的总长度。
- 考虑多种场景:
- 多样本测试:不能只测一支,至少要抽取多支笔(比如10支)进行测试,取平均值,以消除个体差异。
- 不同环境:可以在不同温度、湿度的环境下测试,看环境对笔的寿命有无影响。
- 间歇性使用:模拟真实用户使用场景,写一会、停一会,看是否会影响总书写长度(比如笔尖干涸)。
是的,是我独立排查并定位的。
- Bug现象:在一次大促活动前,我们发现一个非常奇怪的问题:有极少数用户的订单,在支付成功后,订单状态没有变成“待发货”,而是卡在了“待支付”状态,导致用户付了钱但商家无法发货。
- 初步排查:这个问题是偶现的,复现率极低。我首先检查了前端日志和后端订单服务的日志,没有发现明显的错误。我又检查了支付服务的日志和数据库,确认支付是成功的,回调通知也正常发出了。
- 深入分析:问题似乎出在订单服务接收支付回调通知这个环节。我怀疑是消息队列(MQ)出了问题。于是,我让运维同事帮忙,拉取了当时MQ的所有消息记录。通过仔细比对支付时间和订单创建时间,我发现那些出问题的订单,它们的支付成功消息,在MQ里出现了重复消费的情况。
- 定位原因:我拿着这个线索去找开发。最终我们一起定位到,订单服务在消费MQ消息时,对消息的幂等性处理有一处逻辑漏洞。在网络波动等极端情况下,支付成功消息可能会被重复投递。正常情况下,幂等处理会保证订单状态只更新一次。但那个漏洞导致在某种特殊条件下,第二次的重复消息反而会把已经更新为“待发货”的状态给覆盖回“待支付”。
- 印象深刻的原因:这个Bug隐藏得很深,涉及多个微服务之间的异步通信,复现困难。通过层层深入的日志分析和逻辑推理,最终定位到根源,避免了大促时可能出现的重大线上事故,这让我非常有成就感。
我发现的BUG类型很广,主要可以分为几类:
- 功能逻辑错误:这是最常见的,比如优惠券的满减门槛计算错误,退款金额不正确等。
- UI显示问题:比如页面布局错乱、文字重叠、按钮无法点击等。
- 性能问题:比如某个页面加载时间过长,某个接口响应超时。
- 兼容性问题:比如某个功能在Chrome上正常,但在Safari上就无法使用;或者在iOS上正常,在某个Android机型上闪退。
- 数据一致性问题:比如前端显示的用户余额和后端数据库里的不一致。
- 安全性漏洞:比如通过修改URL参数可以查看别人的订单信息(水平越权)。
遇到过,上面提到的那个支付成功后订单状态不流转的Bug,就是一个典型的偶现Bug。
除了上面那个,我还遇到过:
- 特定机型下的闪退:App在某个冷门的Android机型上,进入商品详情页时有一定概率会闪退。最后定位是该机型的WebView内核版本较低,与我们使用的某个前端框架有兼容性问题。
- 高并发下的数据错乱:在压测某个领取优惠券的接口时,发现极少数情况下,一个用户会领到两张相同的、本应限领一张的优惠券。最后定位是并发处理时,一个Redis锁的设置不当导致的。
出现过。完全没有线上Bug是不现实的。我们团队的目标是尽可能减少线上Bug的数量和影响。 我印象比较深的一次是,我们上线了一个新的优惠活动,但配置后台的一个生效时间字段,运营同学误配成了第二天的同一时间。导致上线后,用户看不到活动入口。 这个问题发现得很快,因为我们有**上线后验证(线上Smoke Test)**的流程。我作为该功能的测试负责人,上线后第一时间就去线上环境验证,发现了这个问题,立刻通知运营修改了配置,前后影响不到10分钟,没有造成大的损失。这次事件后,我们也复盘改进了流程,要求所有线上运营配置,都必须有第二个人交叉复核。
是的,我近两年的工作经验主要就是围绕App测试。
App闪退的原因非常多,可以从代码、资源、系统、网络等多个层面分析:
- 代码问题(最常见):
- 空指针异常:调用了未实例化的对象。
- 数组越界:访问了不存在的数组索引。
- 类型转换错误:将一个对象强制转换为不兼容的类型。
- 主线程耗时操作:在UI线程中执行了网络请求、数据库读写等耗时操作,导致ANR(Application Not Responding)。
- 资源问题:
- 内存溢出(OOM):加载了过大的图片或创建了过多对象,导致内存耗尽。
- 资源文件找不到:代码中引用了不存在的图片、配置文件等。
- 系统兼容性问题:
- 调用了高版本系统才有的API,但在低版本系统的手机上运行。
- 不同手机厂商对Android系统的定制,导致兼容性问题。
- 网络问题:
- 网络请求返回的数据格式不符合预期,App没有做相应的异常处理就直接解析,导致崩溃。
- 第三方SDK问题:
- 集成的第三方SDK(如地图、推送、支付SDK)本身存在Bug或兼容性问题。
测过。小程序测试和App、Web测试既有相似之处,也有其特点。
- 相似之处:功能、UI、接口等测试的核心思想是一样的。
- 不同之处:
- 发布机制:小程序需要提交给微信平台审核,发布周期比Web长。
- 性能要求:小程序有包大小限制,对启动速度、加载性能要求更高。
- 依赖微信环境:很多功能强依赖微信提供的API和组件,比如微信登录、微信支付、分享等,需要重点测试。
- 兼容性:主要测试在不同手机、不同微信版本下的兼容性。
由于我们是微服务架构,每个服务都有自己的数据库。我测试订单模块时,最常接触的表有:
- 订单服务:
oms_order(订单主表):存储订单号、用户ID、总金额、订单状态等。oms_order_item(订单商品表):存储订单中的每个商品信息,如商品ID、数量、价格。oms_order_operate_history(订单操作历史表):记录订单状态的每一次流转。
- 用户服务:
ums_member(用户表):查询用户信息。ums_member_receive_address(用户收货地址表)。
- 营销服务:
sms_coupon_history(优惠券使用历史表):查看用户优惠券的状态。
答案同上。
(这个问题问得太细,可能是在压力面试,考察候选人是否真的做过项目) 要全部说出所有表和字段是不现实的,而且也没有必要。我可以挑我最熟悉的订单主表(oms_order) 来举例说明:
id:主键IDorder_sn:订单编号(业务ID)member_id:用户IDtotal_amount:订单总金额pay_amount:实际支付金额freight_amount:运费金额promotion_amount:优惠活动减免金额coupon_amount:优惠券减免金额status:订单状态(0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭)pay_type:支付方式(1->支付宝;2->微信支付)receiver_name:收货人姓名receiver_phone:收货人电话receiver_address:收货人地址create_time:订单创建时间payment_time:支付时间delivery_time:发货时间receive_time:确认收货时间
通过描述这张核心表的关键字段,足以证明我对业务和数据的理解深度。
我们公司主要使用 禅道 进行需求管理。产品经理会在禅道中创建对应产品,将收集的业务需求整理为 “需求” 条目,明确需求描述、优先级、预计工时等信息;对于复杂需求,会拆分成多个子需求或关联任务,分配给开发、测试人员,方便跟踪需求从提出到上线的全生命周期。
缺陷管理同样使用 禅道。禅道的 “缺陷” 模块支持详细记录缺陷现象、复现步骤、预期结果、实际结果等信息,还能直接关联对应的需求、任务或测试用例,测试人员提交缺陷后,开发人员可快速定位问题来源,缺陷状态(未解决、已修复、已关闭等)的流转清晰可见,确保缺陷被及时跟进处理。
我了解 GIRA(推测是你对工具名称的表述偏差),但在实际工作中,我们团队核心使用的是 禅道 进行需求和缺陷管理。不过我对主流项目管理工具的核心逻辑(如需求拆分、任务跟踪、缺陷流转)有一定了解,能够快速适应不同工具的使用。
我们公司使用 禅道 结合 V 模型 进行项目管理。具体使用方式如下:
- 禅道核心功能:在禅道中创建项目后,按 V 模型的阶段拆分工作 —— 需求分析阶段对应 “需求” 模块,记录业务诉求;设计阶段在 “文档” 模块存放设计方案;开发阶段将需求拆分为 “任务” 分配给开发人员,跟踪开发进度;测试阶段通过 “测试用例” 和 “缺陷” 模块执行测试并反馈问题;发布阶段记录上线信息。
- V 模型适配:禅道的阶段划分与 V 模型高度契合,每个开发阶段(如需求分析、概要设计)都对应后续的测试阶段(如验收测试设计、系统测试设计),确保测试活动提前介入,减少后期返工。
我们主要通过 禅道的 “文档” 模块 管理项目资料。在禅道中创建专属项目空间,将需求文档、技术设计文档、测试计划、测试报告等资料按类型分类上传,设置文档访问权限(如仅项目成员可见);同时,文档可关联对应的需求或任务,方便在跟踪工作时快速查阅相关资料,确保信息同步。
我们公司主要使用 SVN(Subversion) 进行版本管理,Windows 环境下搭配 TortoiseSVN(乌龟 SVN) 图形客户端使用,操作直观,无需记忆复杂命令。
SVN (Subversion) 是一款经典的集中式版本控制系统,核心是通过中央服务器存储项目的所有文件版本。Windows 用户常用 TortoiseSVN 图形端,能以可视化方式完成代码的检出、更新、提交等操作,降低使用门槛。
SVN 的核心作用是管理和追踪文件(尤其是代码、配置文件)的变更历史,解决团队协作中的关键问题:
- 版本备份:每次提交都会生成新的版本快照,可随时恢复到任意历史版本,避免文件丢失或错误修改。
- 多人协作:支持多开发人员同时操作同一项目,通过更新、提交机制同步代码,避免本地修改冲突。
- 变更追溯:记录每一次修改的作者、时间、修改内容及提交说明,方便定位问题或回溯变更原因。
结合 TortoiseSVN 图形端,SVN 的核心功能包括:
- 检出 (Checkout):从中央服务器下载项目完整拷贝到本地(图形端右键选择 “SVN Checkout...”)。
- 更新 (Update):将本地文件与服务器最新版本同步(图形端右键选择 “SVN Update”)。
- 提交 (Commit):将本地修改上传到服务器,生成新版本(图形端右键选择 “SVN Commit...”,需填写提交说明)。
- 分支 (Branch) 和 合并 (Merge):从主干创建开发分支(如功能分支、修复分支),完成后合并回主干(图形端通过 “Branch/Tag” 和 “Merge” 选项操作)。
- 版本历史 (Show Log):查看文件或项目的所有修改记录(图形端右键选择 “TortoiseSVN”→“Show Log”)。
当多个人修改同一文件的同一部分时,会出现版本冲突,通过以下步骤解决(以 TortoiseSVN 为例):
- 更新文件:提交前先执行 “SVN Update”,SVN 会尝试自动合并服务器最新版本与本地修改;若合并失败,会在文件中标记冲突区域(如
<<<<<<< .mine对应本地修改、=======分隔、>>>>>>> .rXXX对应服务器版本)。 - 手动编辑:打开冲突文件,根据业务逻辑修改冲突区域,保留正确代码,删除冲突标记。
- 标记已解决:右键冲突文件,选择 “TortoiseSVN”→“Resolved”,告诉 SVN 冲突已处理。
- 提交修改:完成后执行 “SVN Commit”,将解决冲突后的文件上传到服务器。
SVN 的核心操作命令及图形端对应方式如下:
- 检出:命令
svn checkout [服务器仓库URL] [本地目录](简写svn co);图形端右键空白文件夹→“SVN Checkout...”,输入 URL 和本地路径即可。 - 更新:命令
svn update(简写svn up);图形端右键项目文件夹→“SVN Update”。 - 提交:命令
svn commit -m "提交说明"(简写svn ci);图形端右键项目文件夹→“SVN Commit...”,填写说明后提交。
结合 V 模型的测试阶段,我们公司有四套核心环境:
- 开发环境 (DEV):供开发人员调试代码,对应 V 模型的 “单元测试”“集成测试” 阶段。
- 测试环境 (SIT):用于执行系统测试,验证功能是否符合需求,对应 V 模型的 “系统测试” 阶段。
- 预发布环境 (UAT):模拟生产环境配置,供业务人员进行验收测试,对应 V 模型的 “验收测试” 阶段。
- 生产环境 (PROD):最终用户使用的正式环境,上线后持续监控运行状态。
环境的搭建分两部分:
- 基础设施搭建:服务器、网络、操作系统等底层环境由运维团队负责,确保环境稳定性和安全性。
- 应用部署:开发环境和测试环境的应用部署,由开发人员通过自动化工具(如 Jenkins)或手动操作完成;预发布环境和生产环境的部署需经运维团队审核后执行,符合 V 模型各阶段的环境隔离要求。
我具备在已有基础设施上独立搭建测试环境的能力:
- 能根据测试需求,在 Windows 或 Linux 服务器上安装应用依赖(如 JDK、数据库、Web 服务器)。
- 可通过 SVN 检出测试版本代码,配置应用参数,启动服务并验证环境可用性。
- 能处理常见的环境问题(如端口占用、配置错误、服务启动失败),确保测试环境满足系统测试需求。
我们公司的服务器部署在阿里云上,配置和系统根据环境用途区分:
- 开发 / 测试环境:使用 2 核 4G 或 4 核 8G 内存的 ECS 实例,操作系统为 CentOS 7.6,满足日常开发调试和测试执行需求。
- 预发布 / 生产环境:配置更高,如 8 核 16G 或 16 核 32G 内存,搭配 SSD 云盘提升存储性能,操作系统同样为 CentOS 7.6,确保应用稳定运行。
我主要使用 Navicat Premium 连接数据库,它支持 MySQL、Oracle、SQL Server 等多种数据库类型,操作界面直观,可快速执行 SQL 查询、管理数据表和数据,方便测试过程中验证数据正确性。
在 Windows 系统下,我使用 Xshell 通过 SSH 协议连接 Linux 服务器,进行命令行操作(如查看日志、启动服务);同时搭配 Xftp 工具,实现 Windows 本地与 Linux 服务器之间的文件传输(如上传配置文件、下载日志)。
我们公司明确使用 V 模型 进行测试管理。V 模型的核心是 “开发阶段与测试阶段一一对应”:需求分析阶段对应验收测试设计,概要设计阶段对应系统测试设计,详细设计阶段对应集成测试设计,编码阶段对应单元测试设计;测试执行则按单元测试→集成测试→系统测试→验收测试的顺序进行,确保测试覆盖全流程。
V 模型的优缺点如下:
-
优点
:
- 阶段清晰:开发和测试阶段划分明确,便于项目管理和进度跟踪。
- 测试提前介入:测试设计在开发早期(如需求分析、设计阶段)开始,能提前发现需求或设计中的问题,减少后期返工。
- 分工明确:开发人员负责单元测试和集成测试,测试人员专注系统测试和验收测试,职责清晰。
-
缺点
:
- 灵活性不足:是线性模型,各阶段必须按顺序推进,难以适应需求频繁变更的项目。
- 测试依赖开发:系统测试和验收测试需在开发完成后执行,若前期设计存在隐藏问题,可能导致测试阶段大量返工。
- 沟通成本较高:需要开发和测试团队在每个阶段密切协作,若沟通不及时,可能导致需求理解偏差。
在日常测试工作中,自动化测试的投入占比大致如下:
- 功能测试(手动):约 70%,主要覆盖新功能测试、探索性测试等需要人工判断的场景。
- 接口测试(自动化):约 15%,通过 Postman、JMeter 等工具编写自动化脚本,覆盖核心接口的回归测试。
- UI 自动化测试:约 10%,使用 Selenium 框架编写脚本,自动化执行关键业务流程的回归测试。
- 性能测试(自动化):约 5%,通过 JMeter 模拟高并发场景,测试系统的响应速度、稳定性等指标。
是的,我对自动化测试非常感兴趣。自动化测试能有效解决重复测试、回归测试效率低的问题,尤其在迭代频繁的项目中,能大幅提升测试效率;同时,学习自动化测试需要掌握编程、工具使用等技能,能推动我从 “手动测试” 向 “测试开发” 转型,提升自身竞争力。
我接触自动化测试已有一年左右的经验:
- 接口自动化方面,使用 Postman 编写接口测试脚本,设置断言和参数化,通过 Newman 执行批量测试并生成报告。
- UI 自动化方面,使用 Selenium+Python 编写简单的自动化脚本,覆盖登录、下单等核心业务流程。
- 性能测试方面,使用 JMeter 进行接口性能测试,设计测试场景、设置并发数,分析测试结果并提出优化建议。
- 保障产品质量:核心任务是在软件发布前,系统性地找出缺陷(Bug),确保产品能稳定、可靠地运行,符合预定功能
- 规避商业风险:通过减少软件缺陷,直接降低因功能错误、系统崩溃或安全漏洞可能给企业带来的经济损失和品牌声誉损害。
- 提升用户体验:从用户的视角出发,验证产品的易用性、性能和体验,确保交付给用户的不仅是“能用”的,更是“好用”的产品,从而提升用户满意度和信心。
软件测试的核心目的是验证和确认。
- 验证(Verification):确保软件产品在开发过程中的每个阶段都正确地实现了其功能,即“我们是否正确地构建了产品?”(Are we building the product right?)。这通常对应于开发过程中的评审、走查等活动。
- 确认(Validation):确保最终开发出的软件产品满足了用户的真实需求和期望,即“我们是否构建了正确的产品?”(Are we building the right product?)。这通常对应于功能测试、验收测试等活动。 总的来说,核心目的就是通过发现和报告缺陷,来评估和提升软件质量,为软件能否发布提供决策依据,最终降低软件发布后因质量问题带来的商业风险。
我认为测试的核心价值在于风险控制和质量保障。具体体现在三个方面:
- 发现缺陷:这是最直观的价值,通过在产品上线前尽可能多地发现并推动修复缺陷,降低线上故障的风险。
- 建立信心:通过系统全面的测试,为产品经理、开发团队、管理层乃至最终用户建立产品质量的信心,确保产品可以按时、高质量地发布。
- 预防缺陷:测试的价值不仅仅是“找Bug”,更重要的是通过参与需求和设计评审,提前发现逻辑漏洞和潜在问题,将质量控制的环节前移,从源头上减少缺陷的产生。
黑盒测试,也叫功能测试或数据驱动测试。它把被测软件看作一个不透明的“黑盒子”,测试人员完全不关心盒子内部的结构和代码实现,只关心软件的输入和输出。测试人员根据需求规格说明书,设计测试用例,检查软件的功能是否符合预期。
白盒测试,也叫结构测试或逻辑驱动测试。它把被测软件看作一个透明的“白盒子”,测试人员清楚地了解程序的内部结构、逻辑和代码实现。白盒测试的主要目的是检查代码层面的逻辑覆盖率,比如语句覆盖、分支覆盖、路径覆盖等,通常由开发人员执行。
灰盒测试是介于黑盒测试和白盒测试之间的一种测试。测试人员不像白盒测试那样需要深入了解代码的每一行实现,但会利用一些程序内部的知识,比如了解数据库的表结构、接口的实现逻辑等,来辅助设计更具针对性的测试用例。接口测试就是一种典型的灰盒测试。
主要区别在于视角和关注点:
| 特性 | 黑盒测试 | 白盒测试 |
|---|---|---|
| 视角 | 用户视角,外部视角 | 开发者视角,内部视角 |
| 关注点 | 软件功能是否按需求实现 | 代码逻辑是否正确,覆盖率是否达标 |
| 依据 | 需求规格说明书 | 代码、程序设计文档 |
| 测试对象 | 程序的功能 | 程序的内部结构和逻辑 |
| 执行人员 | 测试工程师 | 开发工程师 |
单元测试是对软件中最小的可测试单元进行测试。在面向对象编程中,这个单元通常是一个类或者一个方法。单元测试的目标是验证每个单元的代码逻辑是否正确,它通常由开发人员编写,并且是自动化的。
单元测试的测试对象是类,函数,对象。他们对自己编写的代码进行单元测试,以确保代码单元的质量。
回归测试是指在软件发生了变更(比如修复了缺陷、增加了新功能)之后,重新测试之前已经测试过的功能,以确保这些变更没有引入新的缺陷或导致原有功能产生退化(Regression)。回归测试是保证软件版本迭代质量的重要手段。
复测,也叫重新测试(Re-testing),是指在开发人员修复了一个缺陷之后,测试人员针对这个特定的缺陷进行再次测试,以确认该缺陷已经被成功修复。
| 特性 | 复测 (Re-testing) | 回归测试 (Regression Testing) |
|---|---|---|
| 目的 | 确认特定的缺陷是否已经被修复 | 确认代码变更是否引入了新的缺陷或影响了旧功能 |
| 范围 | 范围很小,仅限于与被修复缺陷相关的测试用例 | 范围可大可小,可能覆盖整个产品或受影响的功能模块 |
| 触发时机 | 在一个缺陷被标记为“已修复”后 | 在代码发生变更(修复Bug、新增功能)后 |
| 关注点 | 缺陷本身 | 变更可能带来的副作用 |
| 举例 | 登录按钮Bug修复了,我再点一下登录按钮看好了没 | 登录按钮Bug修复了,我不仅要测登录,还要测注册、找回密码等功能是否受影响 |
简单说:复测是验证“问题解决了”;回归是验证“没引入新问题”。
冒烟测试(Smoke Testing)是一种在正式测试开始之前,对软件的基本、核心功能进行的一轮快速测试。它的目的是确认软件的主要流程能够跑通,没有阻塞性的、会影响后续测试进行的严重缺陷。如果冒烟测试不通过,那么这个版本会被“打回”,开发需要修复问题后重新提测。
交叉测试通常指兼容性测试中的一种,即在不同的环境下测试软件的功能。这里的“环境”可以指:
- 不同操作系统:如 Windows, macOS, Linux。
- 不同浏览器:如 Chrome, Firefox, Safari。
- 不同设备:如不同品牌、型号、分辨率的手机。 目的是确保软件在各种主流环境下都能正常工作。
- 测试人员交换测试模块的测试
验收测试(Acceptance Testing)是软件上线前的最后一轮测试,其目的是确认软件是否满足了用户的业务需求和合同规定。验收测试通常由最终用户、产品经理或客户来进行。 它分为两类:
- α(阿尔法)测试:在开发环境下,由用户在开发人员的指导下进行测试。
- β(贝塔)测试:在真实的用户环境下,由大量真实用户进行测试,比如软件公测。
安全测试是验证软件系统是否存在安全漏洞,能否抵御恶意攻击的过程。它主要关注系统的保密性、完整性、可用性、认证、授权等方面。常见的安全测试包括SQL注入、跨站脚本(XSS)、权限漏洞(如越权)、文件上传漏洞等。
兼容性测试是检查软件在不同的软硬件平台上是否能够正常运行的测试。
- 对于Web应用,主要是测试在不同浏览器(Chrome, Firefox)、不同操作系统(Windows, macOS)下的兼容性。
- 对于App应用,主要是测试在不同手机品牌(华为、小米、OPPO)、不同操作系统版本(Android 10, 11, 12)、不同分辨率下的兼容性。
功能测试是根据产品的需求规格说明书,验证软件的各项功能是否得到了正确的实现。它不关心内部代码逻辑,只关心输入和输出的结果是否符合预期,是黑盒测试最主要的一种类型。
接口测试是测试系统组件之间接口的一种测试。它主要用于测试服务器端的逻辑,绕过了前端UI,直接向后端服务的接口发送请求,然后验证返回的数据是否正确。接口测试能够更早地发现底层逻辑问题,且执行效率比UI测试高。
性能测试是通过自动化的测试工具,模拟多种正常、峰值以及异常负载条件,来对系统的各项性能指标进行测试。核心指标包括:
- 响应时间:系统处理一个请求所需的时间。
- 吞吐量(TPS/QPS):系统在单位时间内能处理的请求数/事务数。
- 并发用户数:在同一时刻与系统进行交互的用户数量。
- 资源利用率:CPU、内存、磁盘I/O、网络等硬件资源的占用情况。
自动化测试是使用软件工具或脚本来代替人工执行测试用例的过程。它的主要目的是提高测试效率,尤其是在回归测试阶段,可以快速、重复地执行大量用例,从而解放人力,让测试工程师能专注于更复杂的探索性测试和业务逻辑测试。
随机测试,也叫探索性测试(Exploratory Testing)或猴子测试(Monkey Test)。它没有预先定义的测试用例,测试人员根据自己的经验、直觉和对产品的理解,自由地、随机地对软件进行操作,试图发现一些在常规测试中可能被忽略的缺陷。
软件缺陷,通常说的Bug,是指软件中存在的任何不符合用户需求、产品规格或设计文档的问题。
一个更标准的定义是:当且仅当软件的实际结果与预期结果不一致时,就存在一个软件缺陷。这包括:
- 软件未实现需求规格说明书中要求的功能。
- 软件出现了需求规格说明书中指明不应出现的功能。
- 软件实现了需求规格说明书中未提及的功能。
- 软件未达到需求规格说明书中虽未指明但应达到的目标(如性能、易用性)。
- 软件难以理解、不易使用、运行缓慢。
偶现Bug,也叫非必现Bug,是指在特定的、未知的或者难以复现的条件下才会出现的缺陷。它不像必现Bug那样,每次执行相同的操作都能重现。
- 复现困难:这是最核心的特点,可能尝试几十上百次才能出现一次。
- 原因复杂:其产生原因往往与特定环境、特定数据、高并发、多线程资源竞争、内存泄漏等复杂因素有关。
- 定位和修复成本高:因为难以复现,开发人员很难通过调试来定位问题根源,修复周期长。
从功能角度划分,常见的缺陷类型有:
- 功能错误:业务逻辑不正确。
- 界面(UI)错误:布局、样式、文案等显示问题。
- 兼容性错误:在特定环境下功能异常或显示异常。
- 性能问题:响应慢、卡顿、内存占用过高等。
- 安全漏洞:如权限控制不当、信息泄露等。
- 数据错误:数据计算、存储或显示不正确。
- 易用性问题:操作不符合用户习惯,流程繁琐等。
软件缺陷的根源是多方面的,主要包括:
- 需求不明确或变更频繁:这是最主要的根源。需求阶段的错误会导致后续所有阶段的错误。
- 设计错误:系统架构、模块设计存在缺陷。
- 编码错误:开发人员在编码过程中引入的逻辑错误、算法错误等。
- 复杂的软硬件环境:不同环境的差异性导致了兼容性等问题。
- 沟通不畅:产品、开发、测试之间信息传递失真或不及时。
- 时间压力:项目进度紧张,导致开发和测试不充分。
测试用例(Test Case)是为了实施测试而向被测试系统提供的一组集合,这组集合包含:测试环境、操作步骤、输入数据、预期结果。它是测试工作的核心,是衡量测试覆盖度的重要依据。
缺陷报告(Bug Report)是测试人员在发现软件缺陷后,提交给开发人员进行处理的正式文档。它详细描述了缺陷的现象、复现步骤、严重程度、优先级等信息,是测试与开发之间沟通缺陷的重要载体。
测试计划(Test Plan)是在测试工作正式开始之前,编写的指导整个测试过程的纲领性文件。它定义了测试的范围、目标、策略、资源、进度安排以及风险评估。
测试报告(Test Report)是在测试活动结束后,对整个测试过程和结果进行总结的文档。它包含了测试了哪些内容、执行了多少用例、发现了多少缺陷、缺陷的修复情况、遗留风险以及对软件质量的总体评估和是否建议上线的结论。
软件测试可以从不同维度进行分类:
- 按测试阶段划分:单元测试、集成测试、系统测试、验收测试。
- 按是否查看代码划分:黑盒测试、白盒测试、灰盒测试。
- 按是否运行代码划分:静态测试(评审代码、文档)、动态测试(实际运行程序)。
- 按是否自动化划分:手工测试、自动化测试。
- 按测试内容划分:
- 功能性测试:验证功能是否符合需求。
- 非功能性测试:包括性能测试、安全测试、兼容性测试、可靠性测试、易用性测试等。
软件测试有七个基本原则:
- 测试应尽早介入:越早发现缺陷,修复成本越低。
- 测试显示缺陷的存在,但不能证明不存在缺陷:测试只能证明软件有错,不能证明软件没错。
- 穷尽测试是不可能的:即使是简单的程序,输入和路径的组合也可能是天文数字,无法做到完全测试。
- 缺陷具有群集效应(二八原则):软件中80%的缺陷通常集中在20%的模块中。
- 杀虫剂悖论:如果重复使用相同的测试用例,最终将无法发现新的缺陷。测试用例需要定期评审和更新。
- 测试活动依赖于测试背景:不同的软件(如电商App和医疗设备软件),其测试的策略、方法和重点是完全不同的。
- “没有错误”的谬论:即使软件99%的功能都正常,但如果它不满足用户需求,那么它仍然是失败的。
App专项测试是指针对移动应用特性的一些非功能性测试,主要包括:
-
兼容性测试:测试App在不同品牌、型号、系统版本、分辨率的手机上的表现。
-
安装、卸载、更新测试:测试App能否正常安装、卸载,以及覆盖安装或升级后的数据兼容性。
-
性能测试:
- 客户端性能:CPU占用率、内存占用、启动时间、页面响应时间、耗电量、流量消耗。
- 服务端性能:接口的响应时间和吞吐量。
-
网络测试:测试App在不同网络环境(2G/3G/4G/5G/WiFi)和弱网环境下的表现。
-
中断测试:测试在操作过程中,被来电、短信、通知、手机断电、切换网络等事件中断后,App能否正常恢复。
-
权限测试:测试App对相机、通讯录、地理位置等敏感权限的申请和使用是否合理、规范。
详细内容
一、 性能测试
这是专项测试的重中之重,直接关系到用户体验。
-
启动时间 冷启动:App被完全杀死后,从点击图标到首页可操作的时间。 热启动:App在后台运行时,再次切换到前台的时间。 温启动:介于冷热启动之间,例如通过Deep Link打开特定页面。
-
CPU占用率 测试App在各种操作场景下(如复杂页面滚动、数据处理、游戏)对CPU的消耗。过高的占用会导致设备发烫、卡顿和耗电。
-
内存占用与泄漏 内存占用:App运行时的内存使用量。 内存泄漏:对象不再被使用,但无法被垃圾回收器回收,导致内存持续增长,最终可能引发OOM(Out Of Memory)崩溃。
-
流量消耗 测试App在完成特定任务(如下载、视频播放、刷信息流)时消耗的网络数据流量。对于用户来说,这是非常敏感的成本指标。
-
电量消耗 *监测App在前台、后台运行时的耗电情况。定位那些因频繁唤醒CPU、使用GPS或网络请求而异常耗电的“电量杀手”。
-
渲染性能与流畅度 FPS:每秒帧数,衡量界面流畅度。通常要求稳定在50-60fps。 过度渲染:检查同一帧像素被绘制多次的情况,优化UI层级。 卡顿检测:通过分析UI线程的阻塞情况,定位导致掉帧、卡顿的具体原因。
二、 兼容性测试
确保App能在多样化的设备和环境中正常运行。
-
操作系统兼容性 覆盖主流操作系统版本(如Android 10, 11, 12, 13, 14;iOS 14, 15, 16, 17)。 特别注意新系统版本的适配和旧版本的降级处理。
-
设备兼容性 品牌与型号:测试主流厂商的不同型号手机/平板(如华为、小米、OPPO、vivo、三星;iPhone, iPad)。 硬件差异:覆盖不同屏幕尺寸、分辨率、像素密度(DPI)、CPU芯片(如高通、联发科、麒麟)、内存大小等。
-
网络兼容性 在不同网络类型下测试:Wi-Fi(2.4G/5G)、4G、5G。 模拟弱网环境:高延迟、高丢包、低带宽,测试App的稳定性和容错机制。
三、 稳定性测试
确保App不会轻易崩溃或无响应。
-
Monkey / MonkeyRunner测试 通过发送随机的事件流(点击、滑动、按键)来暴力测试App的稳定性,旨在发现潜在的崩溃和ANR。
-
ANR Application Not Responding,应用无响应。通常是因为主线程被长时间阻塞(超过5秒)导致。
-
Crash率收集与分析 通过集成崩溃上报平台(如Bugly, Firebase Crashlytics, Sentry),线上监控App的崩溃率,并定位崩溃堆栈进行修复。
四、 安全测试
保护用户数据和App自身安全。
-
数据存储安全 检查敏感数据(密码、Token、个人信息)是否明文存储在本地。 验证是否使用了安全的加密方式。
-
通信安全 检查网络请求是否使用HTTPS,以及证书校验是否严格,防止中间人攻击。
-
代码安全 防止反编译、代码混淆、加固处理(梆梆固or360天御,目前我们公司用的就是)。 检查日志输出是否泄露敏感信息。
-
权限安全 检查App是否遵循“最小权限原则”,即只申请必要的权限。 测试权限被拒绝时,App的应对逻辑是否合理。
五、 交互与用户体验测试
测试App与设备及其他App的交互。
-
中断测试 模拟来电、短信、低电量提醒、闹钟、切换网络等中断事件,检查App的反应是否正常。
-
通知栏测试 测试通知的发送、显示、点击跳转是否正常。 push消息&短信
-
势与导航测试 测试全面屏手势、物理/虚拟按键与App内导航的兼容性。
-
分享与跳转 测试App与其他App的分享、调起功能(如微信分享、支付宝支付)是否正常。
六、 安装、卸载、覆盖安装与更新测试
-
安装测试:在不同来源(应用商店、直接安装包)下安装是否成功。
-
卸载测试:卸载是否彻底,是否残留用户数据。 3、覆盖安装:在原有低版本的APP基础上直接覆盖安装高版本的APP
-
更新测试: 跨版本升级、小版本升级。 升级后用户数据(如登录状态、缓存、设置)是否得以保留。
七、 后台与推送测试
- 后台保活:App切换到后台后,特定任务的执行情况。
- 进程杀死恢复:App被系统杀死后,再次打开时是否能恢复到之前的状态。
- 推送测试: 推送消息能否准确送达。 点击推送消息能否正确跳转。 多设备登录时的推送逻辑。
-
| 对比维度 | Web 测试 | App 测试 |
|---|---|---|
| 运行载体 | 浏览器 | 手机操作系统 (iOS/Android) |
| 兼容性 | 重点关注不同浏览器和操作系统的组合 | 重点关注不同手机品牌、型号、系统版本、分辨率 |
| 性能 | 关注页面加载速度、后端响应时间 | 除了后端性能,更关注客户端性能(CPU、内存、耗电、流量) |
| 安装 | 无需安装 | 需要测试安装、卸载、更新 |
| 中断场景 | 较少 | 非常多,如来电、短信、断网、切换App、低电量提醒等 |
| 网络环境 | 通常是稳定的有线或WiFi网络 | 网络环境复杂多变,需重点测试弱网和网络切换 |
| 权限 | 浏览器权限较少,如摄像头、麦克风 | 需测试对系统敏感权限(通讯录、定位等)的获取和使用 |
| 发布 | 可随时发布,用户无感知刷新 | 需要打包提交到应用商店审核,发布周期长,用户需手动更新 |
软件的生命周期通常包括六个阶段:
- 需求分析:确定软件需要做什么。
- 计划:评估资源、成本、时间,制定项目计划。
- 设计:进行概要设计和详细设计。
- 编码:将设计转化为代码。
- 测试:对软件进行单元、集成、系统测试。
- 运行与维护:软件上线后的日常维护、更新和修复。
软件测试的生命周期是与软件开发生命周期并行的,主要包括:
- 需求分析:从测试角度分析需求,识别测试点。
- 测试计划:制定整体的测试策略和计划。
- 测试设计:设计和编写测试用例。
- 测试环境搭建:准备测试所需的软硬件环境。
- 测试执行:执行用例,记录结果,提交缺陷。
- 测试报告:测试结束后,进行总结和报告。
-
C/S 架构 (Client/Server):客户端/服务器架构。
- 特点:需要在用户的电脑上安装一个专门的客户端软件,如QQ、微信PC版、大型游戏。
- 优点:客户端可以处理部分业务逻辑,对服务器压力小;界面响应快,表现力强。
- 缺点:开发和维护成本高,客户端需要更新和升级。
-
B/S 架构 (Browser/Server):浏览器/服务器架构。
- 特点:用户通过浏览器就可以访问服务,无需安装客户端,如淘宝、京东等网站。
- 优点:无需安装,维护和升级集中在服务器端,用户无感知。
- 缺点:界面表现力受浏览器限制,对服务器压力较大。
测试的对象非常广泛,不仅仅是程序代码。它包括:
- 文档:需求文档、设计文档、用户手册等。
- 程序:源代码、可执行程序。
- 数据:测试过程中使用的输入数据、数据库中的数据。
- 系统环境:包括硬件、网络、操作系统等。
SQL注入是一种常见的网络攻击方式。攻击者通过在Web应用的输入框或URL参数中,构造并注入恶意的SQL命令,欺骗服务器执行非预期的数据库操作,从而达到窃取、篡改或删除数据的目的。
水平越权,也叫横向越权,是一种权限类的安全漏洞。攻击者通过修改请求中的ID等参数,来访问或操作其他与自己拥有相同权限级别的用户的数据。
举例:用户A登录后,查看自己订单的URL是 .../order?id=101。他尝试将ID改成 102,即 .../order?id=102,如果系统没有做严格的权限校验,就成功看到了用户B的订单,这就是水平越权。
| 特性 | 关系型数据库 (如 MySQL, Oracle) | 非关系型数据库 (NoSQL, 如 Redis, MongoDB) |
|---|---|---|
| 数据结构 | 基于二维表(行和列),结构化存储 | 数据结构灵活,如键值对、文档、图形等 |
| 存储方式 | 存储在磁盘 | 可以存储在内存或磁盘,内存读写速度快 |
| 扩展性 | 通常是纵向扩展(提升单机性能) | 通常是横向扩展(增加服务器节点) |
| 事务 | 遵循ACID特性,事务支持非常完善 | 通常不完全支持或弱化ACID,强调BASE理论(最终一致性) |
| 适用场景 | 需要高数据一致性的业务,如订单、金融 | 高并发、大数据量、对数据一致性要求不那么严格的场景,如社交、缓存 |
- 开源免费:MySQL是开源的,可以免费使用,极大地降低了企业的成本,而Oracle是商业软件,价格昂贵。
- 轻量易用:MySQL体积小,安装和配置相对简单,对硬件要求也较低。
- 社区活跃:拥有庞大的开发者社区,遇到问题很容易找到解决方案。
- 互联网领域广泛应用:与Linux、Apache、PHP/Java/Python等技术栈(即LAMP/LNMP)结合紧密,是绝大多数互联网公司的首选。 而Oracle在传统企业级应用、金融、电信等领域,凭借其强大的稳定性、安全性和复杂查询处理能力,仍然占据主导地位。
一个完整的软件测试流程通常包括以下几个阶段:
- 需求分析阶段:测试人员参与需求评审,理解需求,分析测试点,并评估需求的可测性。
- 测试计划阶段:根据项目规模和周期,制定测试计划,明确测试范围、策略、资源和时间安排。
- 测试设计阶段:根据需求文档,使用等价类、边界值等方法设计测试用例,并组织用例评审。
- 测试执行阶段:在测试环境中执行测试用例,发现并提交缺陷,跟踪缺陷的处理过程。
- 回归测试阶段:在新版本提测后,执行回归测试,确保原有功能未受影响。
- 测试报告阶段:测试结束后,编写测试报告,总结测试过程,评估软件质量,并给出上线建议。
我上家公司遵循的是基于瀑布模型的测试流程,非常规范:
- 需求评审:产品经理组织,开发和测试共同参加,我们会从测试角度对需求提出疑问。
- 测试计划与用例设计:评审后,测试组长会制定测试计划,然后我们根据需求和原型图编写测试用例。
- 用例评审:用例写完后,会组织产品、开发和测试一起进行评审,确保用例的覆盖度和正确性。
- 提测:开发完成功能开发和单元测试后,会向我们提交测试申请单,并部署到测试环境。
- 冒烟测试:收到提测后,我们会先进行一轮冒烟测试,检查主流程是否跑通,不通过则直接打回。
- 系统测试:冒烟通过后,我们开始执行详细的测试用例,进行全面的功能测试、兼容性测试等。
- 缺陷管理:发现的Bug会录入到禅道系统,指派给对应的开发,并跟踪其状态直至关闭。
- 回归测试:通常在上线前,会有一个稳定版本进行多轮回归测试。
- 上线与报告:测试通过后,我们会输出测试报告,然后配合运维进行上线和线上验证。
答案同问题1。
V模型强调了测试与开发的对应关系,左侧是开发阶段,右侧是测试阶段:
- 开发阶段(左侧,自上而下):
- 需求分析
- 概要设计
- 详细设计
- 编码
- 测试阶段(右侧,自下而上):
- 单元测试 (对应 编码)
- 集成测试 (对应 详细设计)
- 系统测试 (对应 概要设计)
- 验收测试 (对应 需求分析)
在V模型中,我主要负责系统测试这个阶段。同时,我也会参与到最顶层的需求分析阶段(进行需求评审)和验收测试阶段(协助用户进行验收)。
- 单元测试:由开发人员执行,测试最小的代码单元(方法、函数)是否正确。
- 集成测试:将多个单元模块组合在一起进行测试,重点测试模块之间的接口和交互是否正确。
- 系统测试:将整个软件系统作为一个整体,在真实的或模拟的运行环境下,对照需求规格说明书,进行全面的功能和非功能测试。
- 验收测试:由最终用户或客户来确认软件是否满足其业务需求,是上线的最后一道关卡。
我们公司的版本上线流程如下:
- 代码冻结:在预定上线日期前,开发会冻结代码分支,不再合入新的功能代码。
- 最终回归:测试团队在预发布环境(Staging)进行最后一轮核心功能回归测试。
- 发布评审:由项目经理组织,产品、开发、测试、运维共同参与,评审测试报告,确认遗留风险,最终决定是否上线。
- 发布窗口:通常在凌晨用户量少的时候,由运维人员执行发布操作。
- 线上验证:发布成功后,测试和开发人员会立即在线上环境对核心功能进行一轮验证(冒烟测试),确保服务正常。
- 发布观察:发布后的一段时间内,相关人员会密切关注监控告警和用户反馈。
灰度发布(又称金丝雀发布)是一种旨在平滑过渡的软件上线策略。
它通过将新版本先推送给一小部分特定用户(如按1%、10%的比例),并在真实环境中观察其性能、稳定性和业务反馈。如果新版本表现良好,则逐步扩大用户覆盖范围,直至完成全量发布。
一旦监控到任何异常或严重问题,可以立即将流量切回旧版本,从而将潜在风险和负面影响控制在最小范围内。该策略能有效降低发布风险,是保障大规模系统稳定和用户体验的关键手段。
测试通过,即允许软件上线,通常需要满足以下标准:
- 用例执行:所有计划内的测试用例都已执行完毕。
- 缺陷收敛:
- 没有致命(Blocker)或严重(Critical)级别的缺陷。
- 一般(Major)级别的缺陷修复率达到95%以上。
- 所有遗留的缺陷都经过产品和项目经理的评审,确认不影响本次上线。
- 功能覆盖:所有本次迭代的核心功能都已测试通过。
- 回归通过:核心功能的回归测试没有发现问题。
- 文档产出:测试报告已编写完成,并对当前版本质量和风险有明确的结论。
答案同问题9。
答案同问题9。
我参加,但主要扮演支持和记录的角色。 我们公司的验收测试(UAT)流程是:
- 准备:在系统测试通过后,我们会准备好一个独立的、数据环境隔离的UAT环境。
- 执行:邀请产品经理和部分种子用户,在UAT环境上,按照我们提供的用户验收测试用例(通常是核心业务流程),进行实际操作。
- 支持:我在现场会为他们演示如何操作,并解答他们的问题。
- 记录:记录他们在测试过程中发现的问题或提出的改进建议,并统一提交到缺陷管理系统。
- 确认:所有严重问题都解决,并且产品经理最终确认软件满足需求后,会签署UAT通过报告。
答案同问题12。
在一个为期两周的迭代周期中,我们通常会经历以下几轮测试:
- 第一轮测试(冒烟+全面测试):在开发提测后,进行冒烟测试,然后开始全面的功能测试,目标是覆盖所有新功能和主要变更点。
- 第二轮测试(缺陷回归):在开发修复完第一轮的大部分Bug后,我们进行集中的缺陷复测,并对受影响的模块进行小范围回归。
- 第三轮测试(全面回归):在上线前,我们会有一个相对稳定的版本,进行一轮全面的回归测试,确保所有功能的稳定性。 所以,严格来说至少有三轮主要的测试。
答案同问题14。
回归测试的轮次和范围是根据风险来定的。
- 小范围回归:在每次修复缺陷后,都会对相关模块进行一轮小回归。
- 全面回归:在上线前的稳定版本上,至少会进行一到两轮的全面回归测试。第一轮全面回归可能会发现一些新的问题,修复后,在上线前会再进行一轮更快速的核心流程回归。
这取决于项目的规模和变更的范围。
- 在一个为期两周的迭代中,如果只是新增了几个小功能,那么最后一轮的全面回归测试可能需要1-2天。
- 如果是一个大的版本重构或增加了核心模块,回归测试可能会持续3-5天,并且我们会优先执行自动化的回归用例集来提高效率。
冒烟测试由测试工程师在开发提测后执行。开发在提测前也要来一次冒烟测试
冒烟测试的核心目的是确认提测版本是否具备可测性。 它通过快速验证软件的核心功能和主流程,来判断这个版本是否存在足以阻塞后续详细测试的严重问题。如果冒烟测试不通过,说明版本质量极差,可以立即打回,从而节省测试人员投入大量时间进行无效测试。
冒烟测试在测试环境下执行。
不一定。理想情况下,开发在提测前应该自测通过,所以冒烟测试应该都能通过。但实际工作中,由于开发疏忽、环境问题、代码合并冲突等原因,冒烟测试不通过的情况也时有发生。
- 用例来源:冒烟测试的用例是我们从完整的测试用例库中,选取出来的一个子集。这个子集覆盖了系统的最核心、最基本的功能流程,比如用户登录、商品浏览、加入购物车、下单等。这些用例通常优先级最高。
- 不通过怎么办:
- 立即中止:一旦发现阻塞性问题,立即停止后续的冒烟测试。
- 记录和沟通:将问题记录到缺陷管理系统,设置为最高优先级,并立即找到对应的开发人员和项目负责人,口头说明问题的严重性。
- 正式打回:发送正式的邮件或在项目沟通群里通知,明确指出冒烟测试不通过,版本被打回,并附上缺陷报告链接,要求开发修复后重新提测。
我们公司通常有以下几套环境:
- 开发环境 (DEV):开发人员自测使用。
- 测试环境 (SIT):我们的主战场,用于执行系统测试、集成测试。
- 预发布环境 (UAT/Staging):与生产环境的配置、数据几乎完全一致,用于上线前的最终回归测试和用户验收测试。
- 生产环境 (PROD):线上真实环境,我们只有只读权限,主要用于上线后的验证。
主要有四套:开发环境、测试环境、预发布环境和生产环境。
- 环境的初始化搭建:由运维(DevOps)工程师负责,包括服务器的配置、网络、数据库的安装等。
- 服务的部署和更新:我们公司已经实现了持续集成和持续部署(CI/CD),开发人员提交代码后,可以通过Jenkins等工具自动部署到开发和测试环境。对于预发布和生产环境,则需要由运维人员手动触发部署流程。
必须需要。我们公司有明确的规定,开发人员在提测前,必须完成单元测试,并且要对自己开发的功能进行基本的冒烟自测,确保主流程能跑通。提测时需要附上自测报告。这是保证提测质量、提高测试效率的重要前提。
通常是一轮正式的评审会议。 但在此之前,我会先请我们测试组内的同事帮忙交叉看一下,进行内部评审。正式评审会议上发现的问题,修改后,我会将更新后的用例发给大家,进行一次线上的、非会议的二次确认。
第一轮正式的评审会议,参与人员通常包括:
- 产品经理:确认用例是否准确理解并覆盖了所有需求。
- 开发工程师(前端和后端):从技术实现的角度,检查用例的逻辑和异常场景是否考虑周全。
- 测试工程师(用例编写者和测试组长):主导评审,并听取各方意见。
- 覆盖度:用例已经覆盖了需求文档中所有的功能点和业务规则。
- 正确性:用例的操作步骤和预期结果与需求一致,没有错误理解。
- 可读性:用例描述清晰、简洁,没有歧义,其他人员也能看懂并执行。
- 完整性:除了正向流程,还充分考虑了各种异常场景、边界条件和兼容性等。
- 无异议:所有参与评审的人员(产品、开发、测试)对用例内容达成共识,没有重大遗漏或争议。
我会从多个维度来综合评估:
- 从缺陷数据看(定量):
- 缺陷数量和密度:发现了多少Bug,平均每个功能点有多少Bug。
- 缺陷严重等级分布:高、中、低级别Bug的比例,是否存在致命或严重Bug。
- 缺陷收敛趋势:随着测试进行,新增Bug的速率是否在下降,这表明版本趋于稳定。
- 从功能覆盖看(定性):
- 核心功能:是否稳定可靠,没有问题。
- 用户体验:软件是否易于使用,响应速度是否流畅,界面是否美观。
- 健壮性:在各种异常操作和环境下,软件是否会崩溃或出现严重错误。
- 从测试过程看:
- 用例通过率:最终的用例执行通过率是多少。
- 遗留风险:有哪些已知的、本次版本不修复的Bug,它们的影响是什么。 最终,我会结合这些定量和定性的信息,在测试报告中给出一个综合的质量评估结论。
答案同问题30。
软件的质量可以根据国际标准ISO/IEC 25010模型来衡量,它包括八个主要特性:
- 功能性 (Functionality):软件是否满足明确和隐含的功能需求。
- 性能效率 (Performance Efficiency):在特定条件下,软件的响应时间、资源消耗等性能表现。
- 兼容性 (Compatibility):软件能否在指定的环境中与其他软件共存和交互。
- 易用性 (Usability):用户理解、学习和使用软件的难易程度。
- 可靠性 (Reliability):软件在规定条件下、规定时间内,维持其功能级别的能力(比如,不容易崩溃)。
- 安全性 (Security):保护信息和数据,防止未授权的访问和使用的能力。
- 可维护性 (Maintainability):软件被修改(如修复缺陷、改进功能)的难易程度。
- 可移植性 (Portability):软件从一个环境迁移到另一个环境的难易程度。
在日常测试中,我们主要关注前六个与外部质量相关的特性。
我会遵循一个系统化的流程:
- 需求分析与澄清:首先,我会仔细阅读需求文档和原型图,确保完全理解业务目标、功能逻辑和验收标准。对于任何模糊或不明确的地方,我会立即找产品经理进行沟通确认。
- 测试点提取:我会使用思维导图(XMind)等工具,从需求中提取出所有的测试点,形成一个测试点大纲。我会从功能、UI、兼容性、性能、安全等多个维度进行分解。
- 测试用例设计:基于测试点大纲,我会运用等价类划分、边界值分析、场景法、错误推测等方法,来设计具体的测试用例。每条用例都会包含清晰的前置条件、操作步骤、输入数据和预期结果。
- 用例评审:设计完成后,我会组织相关人员(产品、开发)进行用例评审,以确保用例的全面性和准确性。
- 测试执行与缺陷管理:评审通过后,在测试环境中执行这些用例,发现问题就提交规范的缺陷报告,并持续跟踪。
答案同问题1的第2、3、4步。我会首先进行需求分析,然后使用思维导图梳理出测试点,最后再根据测试点,运用黑盒测试设计方法编写具体的用例。
最常用的黑盒测试用例设计方法有:
- 等价类划分法:将所有可能的输入数据划分为若干个等价类,从每个等价类中选取一个代表性的数据作为测试用例。这是最基础、最重要的方法。
- 边界值分析法:等价类划分法的一种补充,重点测试输入和输出的边界情况,因为缺陷往往发生在边界值上。
- 场景法(流程分析法):通过模拟用户实际操作的场景,将多个功能点串联起来,形成一个完整的业务流程进行测试。特别适用于测试业务流程复杂的系统。
- 错误推测法:基于经验和直觉,推测程序中可能存在的各种错误,从而有针对性地设计测试用例。
- 因果图/判定表法:适用于输入条件之间存在复杂组合关系的功能。通过表格来列出所有条件的组合和对应的预期结果。
答案同问题3。
- 原则:
- 准确性:用例的预期结果必须是唯一的、正确的。
- 完整性:用例要覆盖所有的需求点,包括正常和异常场景。
- 清晰性:用例描述要清晰、无歧义,便于他人理解和执行。
- 可追溯性:每条用例都应能追溯到对应的需求点。
- 方法: 主要就是运用等价类、边界值、场景法、错误推测、判定表等黑盒测试设计方法。
答案同问题5的“原则”部分。
主要考虑以下几个方面:
- 功能性:是否实现了需求所要求的功能。
- 易用性:操作是否方便,是否符合用户习惯。
- 兼容性:在不同浏览器、操作系统、设备上是否正常。
- 健壮性/可靠性:对于各种异常输入和操作,程序是否会崩溃。
- 安全性:是否存在权限、数据泄露等安全风险。
- 性能:响应速度、资源消耗是否在可接受的范围内。
一份好的测试用例应该具备以下特点(SMART原则的变体):
- 准确性 (Accurate):用例的步骤和预期结果都是正确的。
- 完整性 (Complete):覆盖了所有相关的需求点和场景。
- 清晰性 (Clear):用例描述简洁明了,没有歧义。
- 可执行性 (Executable):用例有明确的前置条件和操作步骤,任何人拿到都可以执行。
- 可重用性 (Reusable):用例设计得当,可以在未来的回归测试中重复使用。
一个标准的测试用例通常包含以下核心要素:
- 用例ID:唯一的标识符。
- 模块/功能点:用例所属的业务模块。
- 用例标题:简洁地概括测试的目的。
- 优先级:标记用例的重要性,如高、中、低。
- 前置条件:执行该用例前需要满足的条件。
- 操作步骤:清晰、分步描述如何执行测试。
- 输入数据:执行步骤中需要输入的具体数据。
- 预期结果:执行完操作步骤后,系统应该展现的正确状态或输出。
- P0 (最高优先级):这是产品的核心功能,是产品得以发布的前提。这类用例通常是冒烟测试的一部分,如果失败,会阻碍后续绝大部分功能的验证。例如,用户的注册和登录功能。
- P1 (高优先级):包含产品的基本功能和重要的错误、边界测试。这些是用例中最常被执行的部分,以保证功能的稳定性。虽然其问题不至于阻塞整个测试流程,但会严重影响产品质量。
- P2 (中优先级):用于更全面地验证功能的各个方面,包括异常流程、中断、UI、兼容性等测试用例。这些功能对于提升用户体验和产品完整性非常重要。
- P3 (低优先级):通常不经常被执行,主要涉及性能、压力、可用性和安全性等非功能性测试,或是针对一些边缘、低频使用的功能
保证用例覆盖率是一个系统性的工作:
- 需求阶段:深入理解和评审需求,是保证覆盖率的前提。只有理解了要测什么,才能谈覆盖。
- 设计阶段:
- 方法论:严格使用等价类、边界值、场景法等科学方法,而不是凭感觉。
- 评审:通过用例评审,借助产品和开发的视角,来发现我们测试思维的盲点和遗漏。
- 工具辅助:我们可以用需求跟踪矩阵,将每一条需求点与对应的测试用例进行映射,确保每条需求都有用例覆盖。
- 持续优化:在测试执行中,以及根据线上反馈,不断地补充和优化我们的测试用例库。
我会通过以下几个方式来保证:
- 个人层面:在设计时,我会严格遵循我刚才提到的方法和原则,并进行自我检查。
- 团队层面:我们会进行同行评审(Peer Review),让组内的其他测试同事帮忙检查,发现我可能没考虑到的点。
- 跨团队层面:我们会组织正式的用例评审会议,让产品和开发参与进来,他们对需求和实现的理解能极大地帮助我们完善用例。 通过这三重保障,可以最大限度地确保用例的质量。
在功能测试层面,我们通常谈论的是需求覆盖率。 计算公式是:需求覆盖率 = (被测试用例覆盖的需求点数量 / 需求总数) * 100% 为了实现这个计算,我们需要一个需求跟踪矩阵(RTM),这个矩阵的行是需求点,列是测试用例ID。通过标记每个用例覆盖了哪些需求点,我们就可以清晰地看到哪些需求被覆盖了,哪些还没有,并最终计算出覆盖率。
这取决于需求的复杂程度。
- 如果是业务逻辑比较简单的功能,比如一个信息展示页面,可能一天能写40-50条。
- 如果是业务逻辑非常复杂的功能,比如订单的优惠计算,可能需要花大量时间去理解逻辑和设计场景,一天可能只能写15-20条高质量的用例。 我认为,用例的质量远比数量重要。
这也取决于用例的复杂度和执行的顺畅度。
- 如果用例步骤简单,且系统比较稳定,一天执行60-80条是可能的。
- 如果用例步骤复杂,需要构造很多前置数据,或者执行过程中发现了很多Bug需要定位和提交,那么一天可能只能执行20-30条。
这没有一个固定的数字,而且也不应该作为衡量测试人员工作的KPI。
- 在测试初期,系统不稳定,可能一天能发现10-20个Bug。
- 在测试后期,系统逐渐稳定,可能几天也发现不了一个Bug。 测试的目标是保障软件质量,而不是单纯地追求Bug数量。有时候,经过一整天的测试没有发现Bug,恰恰说明开发质量高,软件质量好,这同样是测试的价值体现。
一个规范的缺陷报告(Bug Report)通常包含以下要素:
- 缺陷ID:唯一的标识。
- 标题:简洁、准确地概括缺陷问题。格式通常是“【模块】在什么条件下,发生了什么问题”。
- 所属模块/项目/版本:指明缺陷所属的范围。
- 严重等级 (Severity):评估缺陷对软件造成的危害程度。
- 优先级 (Priority):评估缺陷需要被修复的紧急程度。
- 复现步骤 (Steps):清晰、分步描述如何重现该缺陷。
- 实际结果:复现步骤后,系统出现的错误表现。
- 预期结果:根据需求,系统本应有的正确表现。
- 附件:截图、录屏、日志等,帮助开发人员定位问题。
- 提交人/指派给:记录由谁发现,并指派给哪个开发处理。
- 环境信息:操作系统、浏览器、手机型号等。
一个缺陷从被发现到最终解决,会经历一系列的状态流转,这就是它的生命周期。一个典型的生命周期是:
- 新建 (New):测试人员发现并提交缺陷。
- 打开 (Open/Assigned):测试组长或开发组长确认缺陷后,指派给相应的开发人员。
- 已修复 (Fixed/Resolved):开发人员修复了缺陷,并提交代码。
- 重新测试 (Retest/Testing):测试人员在新的版本中,对该缺陷进行复测。
- 已关闭 (Closed):测试人员确认缺陷已修复,关闭该缺陷。
- 其他可能的状态:
- 拒绝 (Rejected):开发人员认为这不是一个缺陷。
- 重新打开 (Reopened):测试人员复测时发现缺陷未修复或修复不彻底。
- 延迟处理 (Deferred):确认是缺陷,但优先级低,当前版本不修复。
主要的状态包括:New, Open, Assigned, Fixed, Retesting, Closed, Reopened, Rejected, Deferred。
- 测试人员发现并提交Bug,状态为
New。 - 测试组长审核Bug,确认有效后指派给开发组长。
- 开发组长将Bug指派给具体的开发人员,状态变为
Open/Assigned。 - 开发人员进行排查和修复。
- 如果确认是Bug并修复,则将状态改为
Fixed。 - 如果认为不是Bug,则改为
Rejected,并给出理由。 - 如果认为无法复现或信息不足,会与测试人员沟通。
- 如果确认是Bug并修复,则将状态改为
- 测试人员在下一个提测版本中,找到状态为
Fixed的Bug进行复测。- 如果修复成功,则改为
Closed。 - 如果问题依然存在,则改为
Reopened,并附上说明,重新指派给开发。
- 如果修复成功,则改为
- 对于
Rejected的Bug,测试人员会与开发、产品共同讨论,如果最终确认不是Bug,则关闭;如果确认是Bug,则重新打开。
严重等级(Severity)是根据缺陷对软件功能的影响程度来划分的,通常分为四个等级:
- 致命 (Blocker/Fatal):导致系统崩溃、主流程完全无法执行、严重数据丢失等问题。
- 严重 (Critical):导致主要功能模块无法使用、严重偏离需求、或者一些非常显眼的UI问题。
- 一般 (Major/Normal):导致次要功能无法使用,或主要功能存在一些不影响使用的瑕疵。
- 轻微 (Minor/Trivial):一些不影响功能使用的UI细节问题、文案错误、易用性建议等。
优先级(Priority)是根据缺陷需要被修复的紧急程度来划分的,通常由产品经理或测试人员来决定,分为四个等级:
P0 - 紧急 (Urgent / Immediate)
- 定义:最高优先级。通常指导致核心功能完全阻塞、系统崩溃、数据丢失或有严重安全漏洞的缺陷,使得后续测试无法进行。
- 处理:必须立即修复,开发人员需要中断当前所有其他工作来解决,通常要求在24小时内修复。
P1 - 高 (High)
- 定义:指严重影响产品主要功能、关键业务流程无法完成或用户体验受到极大损害的缺陷。
- 处理:应在当前版本发布前必须修复。这是下一个开发冲刺(Sprint)中需要优先处理的任务。
P2 - 中 (Medium)
- 定义:指影响次要功能或存在操作不便的缺陷,但用户可以找到规避方法,不影响核心功能的使用。例如,提示信息不准确、部分界面显示问题等。
- 处理:可以纳入正常排期,在后续版本中进行修复。
P3 - 低 (Low)
- 定义:对功能影响微乎其微的缺陷,多为UI瑕疵、错别字或用户体验上的微小建议。这类问题不影响用户使用。
- 处理:优先级最低,可在资源充裕时修复,或作为未来优化的参考。
这是一个经典问题。
- 严重程度 (Severity):是一个技术层面的评估,描述的是Bug本身对系统造成的破坏力有多大。它相对客观。
- 优先级 (Priority):是一个业务层面的评估,描述的是这个Bug需要被修复的紧急性有多高。它相对主观,可能受到项目进度、商业价值等因素的影响。
两者的关系:
- 通常,严重程度高的Bug,优先级也高(比如系统崩溃)。
- 但存在例外:
- 高严重性,低优先级:比如在某个非常冷门、几乎无人使用的功能中,有一个会导致系统崩溃的Bug。因为影响范围小,可以暂时不修。
- 低严重性,高优先级:比如公司官网首页的Logo显示错误。这个Bug本身不影响任何功能,严重性很低,但它直接影响公司形象,所以必须立即修复,优先级非常高。
它们之间没有绝对的、一一对应的关系。需要根据具体情况来判断。 一般来说:
- 致命 (Blocker) 的Bug,优先级通常都是 高 (High)。
- 严重 (Critical) 的Bug,优先级通常是 高 (High) 或 中 (Medium)。
- 一般 (Major) 的Bug,优先级通常是 中 (Medium) 或 低 (Low)。
- 轻微 (Minor) 的Bug,优先级通常是 低 (Low)。
通常是**严重等级为“轻微”或“一般”,且优先级为“低”**的缺陷,可以考虑延迟修复。 比如一些不影响核心功能的UI显示问题、或者在非核心流程中的一些体验优化建议。这些缺陷需要经过产品经理的确认,并记录在案,放入后续的版本迭代计划中。
在我的经验中,“一般 (Major/Normal)” 等级的缺陷是发现得最多的。
- 致命和严重的缺陷,通常在开发自测和测试早期就会被发现和修复,数量相对较少。
- 轻微的缺陷虽然也很多,但有时候测试人员会把一些非常细小的UI问题或建议合并提交,或者在时间紧张时暂时忽略。
- 而“一般”等级的缺陷,比如次要功能的逻辑错误、边界条件处理不当等,数量上是最庞大的。
- 确保可复现:提交前自己要能稳定复现,避免提交偶现或无法复现的Bug。
- 信息完整:遵循缺陷报告的要素,确保标题、步骤、结果、截图等信息齐全。
- 描述精准:标题和描述要简洁、准确,让开发人员一眼就能看懂问题是什么。
- 单一职责:一个缺陷报告只描述一个问题,不要把多个不相关的问题写在一起。
- 初步定位:在提交前,可以做一些初步的分析,比如抓包看看是前端请求问题还是后端返回问题,或者看看日志里的报错信息,这能极大提高沟通效率。
- 态度友好:描述问题时对事不对人,保持专业的态度。
一条高质量的Bug应该做到“5C原则”:
- Correct (准确):确保提交的每个信息都是准确的。
- Clear (清晰):描述简洁明了,没有歧义。
- Concise (简洁):只包含必要的信息,不说废话。
- Complete (完整):包含了复现问题所需的所有信息(步骤、数据、环境、截图、日志等)。
- Consistent (一致):遵循团队统一的Bug报告规范和术语。
- 确保可复现:提交前自己要能稳定复现,避免提交偶现或无法复现的Bug。
- 信息完整:遵循缺陷报告的要素,确保标题、步骤、结果、截图等信息齐全。
- 描述精准:标题和描述要简洁、准确,让开发人员一眼就能看懂问题是什么。
- 单一职责:一个缺陷报告只描述一个问题,不要把多个不相关的问题写在一起。
- 初步定位:在提交前,可以做一些初步的分析,比如抓包看看是前端请求问题还是后端返回问题,或者看看日志里的报错信息,这能极大提高沟通效率。
- 态度友好:描述问题时对事不对人,保持专业的态度
一个规范的缺陷报告(Bug Report)通常包含以下要素:
- 缺陷ID:唯一的标识。
- 标题:简洁、准确地概括缺陷问题。格式通常是“【模块】在什么条件下,发生了什么问题”。
- 所属模块/项目/版本:指明缺陷所属的范围。
- 严重等级 (Severity):评估缺陷对软件造成的危害程度。
- 优先级 (Priority):评估缺陷需要被修复的紧急程度。
- 复现步骤 (Steps):清晰、分步描述如何重现该缺陷。
- 实际结果:复现步骤后,系统出现的错误表现。
- 预期结果:根据需求,系统本应有的正确表现。
- 附件:截图、录屏、日志等,帮助开发人员定位问题。
- 提交人/指派给:记录由谁发现,并指派给哪个开发处理。
- 环境信息:操作系统、浏览器、手机型号等。
一个规范的缺陷报告(Bug Report)通常包含以下要素:
- 缺陷ID:唯一的标识。
- 标题:简洁、准确地概括缺陷问题。格式通常是“【模块】在什么条件下,发生了什么问题”。
- 所属模块/项目/版本:指明缺陷所属的范围。
- 严重等级 (Severity):评估缺陷对软件造成的危害程度。
- 优先级 (Priority):评估缺陷需要被修复的紧急程度。
- 复现步骤 (Steps):清晰、分步描述如何重现该缺陷。
- 实际结果:复现步骤后,系统出现的错误表现。
- 预期结果:根据需求,系统本应有的正确表现。
- 附件:截图、录屏、日志等,帮助开发人员定位问题。
- 提交人/指派给:记录由谁发现,并指派给哪个开发处理。
- 环境信息:操作系统、浏览器、手机型号等。
- 核对需求:首先,我会重新查阅需求文档或原型图,确认我的预期结果是否正确,程序的当前表现是否真的与需求不符。
- 排除环境/数据问题:我会尝试清理缓存、更换浏览器/账号、重置测试数据等方式,来排除是否是由于我本地的特定环境或脏数据导致的问题。
- 尝试复现:我会严格按照操作步骤,多尝试几次,确保这个问题是稳定复现的,而不是我的偶然操作失误。
- 与同事确认:如果我仍然不确定,我会找身边的测试同事或者产品经理,让他们帮忙看一下,确认我们对需求的理解是否一致。 经过以上步骤,我才能最终确认这是一个需要提交的有效Bug。
我们公司的用例评审流程如下:
- 准备:用例编写者在评审前,会将测试用例和相关的需求文档提前发给所有参会人员。
- 会议:
- 由用例编写者(通常是我)来主导会议,逐一讲解我设计的测试用例,特别是针对复杂业务逻辑和异常场景的设计思路。
- 产品经理会检查用例是否覆盖了所有需求点,业务逻辑是否正确。
- 开发人员会从技术实现的角度,补充一些我们可能忽略的边界条件或技术风险点。
- 记录:我会记录下评审过程中提出的所有问题和建议。
- 修改与确认:会后,我会根据评审意见修改和完善测试用例,并将最终版发给大家进行确认。
用例评审的作用非常大,它是一种**“测试前移”**的体现:
- 保证用例质量:通过集思广益,可以发现用例设计中的遗漏和错误,提升用例的覆盖度和准确性。
- 统一团队理解:评审过程是产品、开发、测试三方对需求细节再次达成共识的过程,可以避免因理解不一致导致的后期返工。
- 提前发现缺陷:在评审用例的过程中,常常会发现需求本身的设计漏洞或技术实现的难点,这相当于在编码前就发现并修复了“需求Bug”或“设计Bug”。
用例评审通常在开发人员进行详细设计或编码阶段进行。 这个时间点是最佳的,因为:
- 测试人员已经基于需求文档完成了用例初稿。
- 开发人员也已经开始思考技术实现,能够从技术角度给出有效建议。
- 此时距离开发提测还有一段时间,评审中发现的任何问题,无论是需求、设计还是用例本身,都还有时间去修改。
需求评审的目的是:
- 确保需求的清晰、完整和可测性:作为测试人员,我们的主要任务是检查需求是否存在逻辑矛盾、描述模糊、遗漏场景等问题,确保需求是可以被测试的。
- 统一团队认知:让产品、开发、测试对要做什么、为什么做、做到什么程度达成一致的理解。
- 风险预估:提前识别出项目在技术或业务上的风险点和难点,为后续的计划和设计提供输入。
当然有,而且很频繁。用例评审的主要目的之一就是优化和补充。 比如,有一次我测试一个用户上传头像的功能,我只考虑了正常的图片格式(JPG, PNG)和大小限制。在评审时,开发同学就补充了几个点:
- 上传一个非图片格式的文件(如 .txt)会怎样?
- 上传一个损坏的图片文件会怎样?
- 上传一个带有恶意脚本的“图片”会怎样? 这些都是我从纯黑盒角度容易忽略的,通过评审,让我的用例覆盖得更全面了。
我会本着对事不对人、以理服人的原则来处理:
- 重新审视:首先,我会再次检查我的缺陷报告,确认我的复现步骤是否清晰,预期结果是否来自确切的需求文档,排除是我自己搞错了的可能性。
- 线下沟通:我会主动找到这位开发同事,当面为他复现一次这个Bug,并心平气和地向他解释为什么我认为这是一个Bug,依据是哪一条需求。
- 引入第三方:如果沟通后我们仍然无法达成一致,我会将这个问题上升,引入产品经理来判断。因为需求的最终解释权在产品经理。由他来裁定,这究竟是一个Bug,还是一个新的需求,或者是“设计如此”。
- 接受结论:无论最终结论如何,我都会接受并尊重。如果是Bug,就修复;如果不是,就关闭。重要的是通过沟通,让大家对产品行为达成共识。
我会委婉但明确地拒绝。 我会这样和他说:“我理解项目进度紧,大家压力都很大。但我的职责就是保证产品质量,对用户负责。发现问题并提出来,是为了让我们的产品更好,避免上线后出问题造成更大的麻烦。我们是一个团队,目标是一致的。如果你觉得我提的哪个Bug不合理,我们可以公开讨论,但‘少提Bug’这个原则性的问题,我必须坚持。” 我会强调,提Bug不是针对他个人,而是对事不对人,是为了整个项目的成功。
首先,我会分析他不修复的原因,然后针对性地解决:
- 如果是优先级问题:他可能觉得这个Bug不重要,手头有更紧急的任务。我会和他以及产品经理沟通,重新评估这个Bug的优先级,如果确实很紧急,就请产品经理协调资源。
- 如果是技术难题:他可能暂时没有找到解决方案。我会表示理解,并询问是否需要我提供更多信息或协助他复现、定位。
- 如果是“不是Bug”的争议:参考问题38的回答,引入产品经理来裁定。
- 如果纯粹是态度问题(虽然很少见):我会先尝试沟通,如果无效,我会把情况上报给我的测试组长,由他出面与开发组长进行沟通协调。
- 优先级低:认为缺陷不重要,或有更紧急的工作。
- 不是缺陷:认为程序的行为是符合设计或需求的("It's not a bug, it's a feature")。
- 无法复现:在他那边无法复现出问题。
- 非职责范围:认为这个问题是其他人或模块引起的。
- 修复成本高:修复这个问题需要改动大量代码,风险很高,得不偿失。
- 设计如此:当前的技术架构或设计限制,导致这个问题难以修复。
- 时间不足:项目即将上线,没有时间修复非关键性问题。
我们公司使用禅道(ZenTao) 来进行测试用例的管理。禅道可以很好地将需求、任务、用例和缺陷关联起来。在之前的公司,我也用过 TestRail 和 Excel。
我们主要使用 Jira。Jira的功能非常强大,工作流可以高度定制,便于我们进行缺陷的生命周期管理和状态跟踪。
不一定。这取决于不修复的Bug是什么。
- 如果是致命(Blocker)或严重(Critical)级别的Bug,那么测试绝对不能通过。
- 如果是一般(Major)或轻微(Minor)级别的Bug,需要经过产品经理和项目相关方的共同评审。如果大家一致认为这个Bug对当前版本影响不大,可以接受其风险,并计划在后续版本修复,那么测试可以有条件地通过。但我们必须在测试报告中明确记录这些遗留的已知问题和风险。
不完全是。在一定程度上,发现的缺陷数量多,可以反映出软件质量可能较差。但是:
- 测试能力影响:一个经验丰富的测试团队可能会比一个新手团队在同样质量的软件中发现更多的Bug。
- 测试阶段影响:在测试早期,发现的Bug数量会很多;到后期,版本稳定,发现的Bug会越来越少。
- 软件复杂度:复杂的软件本身就更容易产生缺陷。 所以,不能简单地用“发现的Bug数量”来绝对衡量软件的质量,而应该结合缺陷的严重等级、所在模块、收敛趋势等多个维度来综合判断。
等价类划分法是一种黑盒测试设计方法。它将程序的输入域划分为若干个互不相交的子集,这些子集被称为“等价类”。我们假设,同一等价类中的所有输入数据,对于揭露程序中的错误来说,其效果是等效的。我们只需要从每个等价类中选取一个代表性的数据作为测试用例,就可以覆盖到这一整类的数据。 它分为有效等价类和无效等价类。
边界值分析法是等价类划分法的一种重要补充。大量的实践证明,程序中的错误最容易发生在输入或输出范围的边界上。因此,边界值分析法就是要有意地选择等价类边界及其两侧的值作为测试用例。 例如,一个输入框要求输入1-100的整数,根据边界值法,我们应该测试 0, 1, 2, 99, 100, 101 这几个值。
它的核心作用是用最少的测试用例,高效地发现因边界条件处理不当而导致的缺陷。它能极大地提升测试的“性价比”,是对等价类划分法的重要强化。
错误推测法是基于测试人员的经验、知识和直觉,来推测程序中可能存在的错误类型,并据此设计测试用例。这是一种非系统性的方法,但非常有效。 例如,有经验的测试人员会去测试输入框中输入空值、特殊字符、超长字符串等,或者在进行关键操作时频繁点击、快速刷新页面等,这些都是错误推测法的应用。
场景法,也叫流程分析法,是通过模拟用户实际使用软件时的各种场景来设计测试用例的方法。它不关心单个功能点的细节,而是将多个功能点串联成一个完整的业务流程。 基本流程:它通常有一个基本流(最正确、最常见的流程)和多个备选流(各种分支和异常流程)。
以电商购物为例:
- 确定场景:比如“一个已登录的普通用户,成功购买一件商品”。
- 画出流程图:用流程图画出这个场景的主干流程和所有可能的分支。
- 基本流:登录 -> 搜索商品 -> 查看详情 -> 加入购物车 -> 结算 -> 选择地址和支付方式 -> 提交订单 -> 支付成功。
- 备选流:
- 搜索不到商品怎么办?
- 商品库存不足怎么办?
- 结算时使用了优惠券会怎样?
- 支付失败了怎么办?
- 中途取消订单会怎样?
- 生成测试用例:基于流程图,将每一条从开始到结束的完整路径,都设计成一条或多条测试用例。
我没有专门做过深度的安全测试,因为这通常需要专业的安全工程师来负责。但在日常的功能测试中,我会进行一些基本的、常见的安全点测试,比如:
- SQL注入:在输入框中输入一些简单的SQL关键字(如
or 1=1)看是否会报错或绕过登录。 - XSS(跨站脚本):在输入框中输入
<script>alert(1)</script>看是否会弹窗。 - 越权测试:测试水平越权和垂直越权,比如尝试通过修改URL中的ID来访问不属于自己的数据。
- 密码安全:检查密码在传输和存储时是否是加密的。
做过,交叉测试是兼容性测试和人与人交换模块的测试
在软件开发中,交叉测试(也称为跨平台兼容测试)是验证软件应用在多种平台、设备或浏览器上都能正常运行的过程, 其主要目的是确保所有用户无论使用何种环境,都能获得一致且良好的用户体验。
团队协作中的交叉测试:在某些软件开发实践中,交叉测试也指由不同的团队或个人相互测试彼此开发的代码或功能模块,这种做法有助于促进团队间的协作和知识共享,并能以新的视角发现潜在的缺陷。
我们的交叉测试主要针对Web端和App端:
- Web端:我们会维护一个主流浏览器和操作系统的矩阵表。比如,我们会测试产品在
Windows平台的Chrome、Firefox浏览器,以及macOS平台的Chrome、Safari浏览器上的功能和UI表现。 - App端:我们会选取市场上占有率最高的几个品牌(如华为、小米、OV)的热门机型,以及覆盖高中低端的不同Android版本,进行测试。我们公司有几十台常用的测试真机。对于更多的机型,我们会借助云测平台(如Testin)来完成。
兼容性测试侧重的方面主要有:
- 功能:所有核心功能在不同环境下是否都能正常使用。
- UI:页面布局、样式、字体、图片在不同分辨率和浏览器内核下是否显示正常,没有错位或变形。
- 数据:在不同环境下操作产生的数据是否能互通和保持一致。
会的。除了操作系统、浏览器、设备这些平台兼容性,我们还会考虑:
- 软件间兼容:我们的App在运行时,与其他常用App(如微信、输入法)是否会发生冲突。
- 数据兼容:当App进行版本升级后,旧版本产生的用户数据能否被新版本正确识别和使用。
- 网络兼容:在不同网络运营商(移动、联通、电信)的网络下,功能是否正常。
这是一个很常见的问题,主要区别在于:
| 对比维度 | Web 测试 | App 测试 |
|---|---|---|
| 运行载体 | 浏览器 | 手机操作系统 (iOS/Android) |
| 兼容性 | 重点关注不同浏览器和操作系统的组合 | 重点关注不同手机品牌、型号、系统版本、分辨率 |
| 性能 | 关注页面加载速度、后端响应时间 | 除了后端性能,更关注客户端性能(CPU、内存、耗电、流量) |
| 安装 | 无需安装 | 需要测试安装、卸载、更新 |
| 中断场景 | 较少 | 非常多,如来电、短信、断网、切换App、低电量提醒等 |
| 网络环境 | 通常是稳定的有线或WiFi网络 | 网络环境复杂多变,需重点测试弱网和网络切换 |
| 权限 | 浏览器权限较少,如摄像头、麦克风 | 需测试对系统敏感权限(通讯录、定位等)的获取和使用 |
| 发布 | 可随时发布,用户无感知刷新 | 需要打包提交到应用商店审核,发布周期长,用户需手动更新 |
- Web端:
- 界面:主要关注不同分辨率下的响应式布局,以及不同浏览器内核对CSS样式的渲染差异。
- 交互:主要交互方式是鼠标的点击、悬停、滚动和键盘的输入。
- App端:
- 界面:主要关注在不同尺寸和分辨率的手机屏幕上的适配问题。
- 交互:交互方式更丰富,除了点击,还有滑动、长按、双指缩放等多种手势操作。还需要测试横竖屏切换时的界面表现。
定位Bug是一个由表及里、逐步缩小范围的过程:
- 复现问题:首先要能稳定地复现Bug,并仔细观察现象。
- 区分前端/后端:这是最关键的第一步。我会打开浏览器的开发者工具(F12):
- 看Console:检查控制台是否有JS报错。
- 看Network:查看接口请求。如果请求没发出去,或请求参数错误,很可能是前端问题。如果请求正常,但返回的响应数据不对或报错(如500错误),那基本就是后端问题。
- 后端问题定位:
- 看日志:如果确定是后端问题,我会登录到Linux服务器,使用
tail、grep等命令查看对应服务的日志文件,查找ERROR或Exception关键字,这通常能提供最直接的线索。 - 查数据库:根据日志信息,我会去数据库里检查相关的数据是否正确,比如一个订单状态没更新,就去订单表里看
status字段的值。
- 看日志:如果确定是后端问题,我会登录到Linux服务器,使用
- 环境和数据排查:如果以上步骤还没找到问题,我会考虑是否是特定测试环境或测试数据导致的问题,尝试在不同环境或用不同账号复现。
- 与开发沟通:如果我自己无法定位,我会把我的排查过程和收集到的所有信息(报错截图、日志、请求响应报文等)一并提供给开发,和他一起进行定位。
主要通过浏览器的**开发者工具(F12)**来判断:
- 前端Bug的特征:
- 界面显示问题:布局错乱、样式错误、兼容性问题。
- 交互问题:点击按钮没反应、动画效果异常。
- JS错误:
Console控制台有红色的JS报错信息。 - 请求问题:
Network中看到请求没有发出去,或者请求的URL、参数、请求头有误。
- 后端Bug的特征:
- 数据问题:前端界面显示的数据与预期不符(比如商品价格错误),但请求参数是正确的。
- 服务器错误:
Network中看到接口返回的状态码是5xx(如500 Internal Server Error, 502 Bad Gateway)。 - 业务逻辑错误:前端请求参数都正确,但后端处理业务逻辑后返回的结果不符合需求(比如优惠券计算错误)。
- 性能问题:接口响应时间过长(Pending时间很久)。
答案同问题14和15。核心就是利用浏览器开发者工具作为分界点,先判断责任田,然后再深入到各自的领域(前端看JS报错,后端看服务日志和数据库)去查找根本原因。
在我上一家公司,我们的测试工作投入占比大概是这样的:
- 功能测试:占比最大,大约 70%。这是保证业务功能正确性的基础。
- 接口测试:占比约 15%。主要在新接口提测时进行手动测试,以及对核心接口编写自动化脚本。
- 自动化测试(UI自动化和接口自动化):总共占比约 10%。主要用于核心业务流程的回归测试。
- 性能测试:占比约 5%。主要是在大促活动前,对核心交易链路进行压力测试。
我接触和实践自动化测试大概有一年半的时间。主要是利用业余时间和项目间隙,学习并应用Python+Selenium进行Web的UI自动化,以及使用Python+Requests进行接口自动化。我能够独立编写和维护测试脚本,并对公司的核心回归用例集做过一些贡献。
是的,这是我非常明确的职业目标之一。我认为自动化是提升测试效率和价值的关键技术方向,也是衡量一个测试工程师技术能力的重要标准。我希望在未来的工作中,能有更多的机会深入实践和研究自动化测试,比如参与框架的搭建和优化、探索与CI/CD的深度集成等。
如果我是项目唯一的测试人员,我会这样安排:
- 理解与规划 (20% 时间):
- 深入理解需求,与产品和开发充分沟通,明确测试范围和目标。
- 制定详细的测试计划,包括时间安排、资源需求(如测试账号、环境)、测试策略(重点测什么,次重点是什么)。
- 进行风险评估,识别潜在的风险点并制定应对预案。
- 设计与准备 (30% 时间):
- 设计测试用例,并组织评审。
- 准备测试数据和测试环境。
- 执行与跟踪 (40% 时间):
- 执行测试用例,提交和跟踪缺陷。
- 与开发保持紧密沟通,推动问题解决。
- 进行多轮回归测试。
- 总结与报告 (10% 时间):
- 编写测试报告,总结测试过程,评估产品质量。
- 参与项目复盘,总结经验教训。
如果我是测试经理,需要考虑的会更宏观:
- 资源评估:评估项目的规模、复杂度和时间要求,判断需要投入多少测试人力。
- 团队分工:根据团队成员的特点和能力,进行合理的任务分配。比如让业务熟悉的老员工负责核心模块,让新人负责次要模块或辅助测试。
- 制定测试策略:
- 确定测试类型:这个项目需要进行哪些测试?(功能、接口、性能、安全?)
- 确定测试重点:哪些是核心模块,需要重点投入资源?哪些是高风险区域?
- 自动化策略:哪些场景适合自动化?投入产出比如何?
- 流程与规范:确保团队遵循统一的测试流程、用例规范、缺陷管理规范。
- 进度与风险控制:
- 制定整体的测试计划和里程碑。
- 持续跟踪测试进度,及时发现并解决阻塞问题。
- 动态评估项目风险,并向项目组和上级汇报。
- 沟通与协作:建立高效的内外部沟通机制,协调好与产品、开发、运维等团队的关系。
- 质量度量与报告:建立质量度量指标(如Bug密度、修复率),并定期输出质量报告。
提高测试质量需要从流程、技术、人员三个方面入手:
- 流程优化:
- 测试左移:尽早介入,加强需求和设计评审,从源头预防缺陷。
- 规范化:建立并执行统一的测试流程、用例规范、缺陷标准。
- 复盘文化:定期进行项目复盘,总结经验,持续改进。
- 技术驱动:
- 引入自动化:对回归场景实现自动化,提高效率和覆盖率。
- 分层测试:建立单元测试、接口测试、UI测试的金字塔模型,将测试重点放在更稳定、执行更快的下层。
- 工具赋能:引入更高效的测试工具和平台。
- 人员发展:
- 技能培训:定期组织技术和业务培训,提升团队的专业能力。
- 知识共享:鼓励团队成员之间分享经验和最佳实践。
- 激励机制:建立合理的激励机制,鼓励员工发现有价值的深层次缺陷。
答案同问题22。作为团队,更侧重于流程的建立和执行,以及团队整体能力的提升。
写过。在每个大的版本迭代开始时,测试组长会编写总体的测试计划,然后我会根据我负责的模块,编写更详细的模块测试计划。
一个完整的测试计划通常包括:
- 项目背景:介绍项目目标和背景。
- 测试范围:明确本次测试要覆盖的功能模块和特性。
- 测试目标:定义测试要达到的质量标准。
- 测试策略:采用哪些测试方法和技术。
- 资源计划:需要的人员、硬件、软件资源。
- 进度安排:定义各个测试阶段的起止时间和里程碑。
- 风险评估与对策:识别潜在风险并制定应对计划。
- 人员分工:明确每个人的职责。
- 准入/准出标准:定义开始测试和结束测试的条件。
我认为关键在于明确性和风险意识:
- 明确性:
- 范围明确:清晰地定义“测什么”和“不测什么”。
- 目标明确:本次测试要达到的质量目标是什么(如Bug修复率、用例通过率)。
- 责任明确:谁在什么时间负责什么任务。
- 风险意识:
- 风险识别:能够提前识别出项目中可能存在的各种风险(如需求变更、技术不成熟、时间紧张等)。
- 应对预案:针对已识别的风险,提前制定好应对策略。 一个好的测试计划,不仅是任务清单,更是项目测试的“作战地图”和“风险雷达”。
我认为需求分析和测试设计阶段最重要。 虽然测试执行是发现Bug的直接手段,但它的效果完全依赖于前期的设计。如果需求理解有偏差,或者测试用例设计得有遗漏,那么即使执行得再完美,也无法发现那些“我们没想到要去测”的Bug。 这个阶段是“测试左移”思想的核心体现,它决定了测试的方向和深度。在这个阶段多投入一分精力,可以在后期节省十分的返工成本。
测试过程中的风险主要有:
- 需求风险:需求不明确、频繁变更,导致测试范围和依据不稳定。
- 技术风险:采用新技术或复杂架构,导致不可预见的问题增多。
- 进度风险:开发延期提测,导致测试时间被严重压缩。
- 资源风险:测试人员不足、测试设备或环境不稳定。
- 质量风险:提测版本质量过差,Bug过多,导致测试进度缓慢;或者遗留了未知的严重缺陷。
除了上述常见的风险,还可能存在:
- 沟通风险:团队成员之间沟通不畅,信息传递有误。
- 回归不充分风险:由于时间或资源限制,回归测试范围不足,导致引入新问题。
- 第三方依赖风险:项目依赖的第三方服务(如支付、物流接口)不稳定或发生变更。
最常见的情况是开发延期提测。 其他原因还包括:
- 项目前期对开发和测试工作量的评估过于乐观。
- 测试过程中需求发生重大变更。
- 提测版本质量太差,修复Bug和回归占用了大量时间。
- 测试环境不稳定,频繁中断测试。
我会采取一套组合拳来应对:
- 第一时间沟通:立即向我的上级和项目经理汇报情况,说明当前的时间缺口和潜在的质量风险,让所有人都意识到问题的严重性。
- 调整测试策略:与产品、开发共同评审,对测试范围进行优先级排序。
- 优先保证:核心业务流程、主要新增功能的测试。
- 降低优先级:次要功能、UI细节、低级别的Bug验证。
- 考虑放弃:一些非常边缘的功能或兼容性测试。
- 提升测试效率:
- 增加资源:申请加班,或者看能否协调其他组的同事临时支持。
- 探索性测试:对于次要功能,可以采用经验丰富的测试人员进行探索性测试,来代替执行详细的用例,以求在短时间内覆盖更多功能。
- 加强沟通:与开发保持紧密沟通,发现阻塞性问题立刻解决,减少等待时间。
- 明确风险:在测试报告中,明确指出由于时间不足,哪些部分测试不充分,可能存在哪些遗留风险,为管理层决策提供依据。
答案同问题4。核心思路就是:沟通、排序、提效、报告风险。
答案同问题4。这是最典型的场景,处理方法完全一致。
答案同问题4。在这种高压情况下,风险排序和高效沟通变得尤为重要。我会聚焦于保障最高优先级的核心功能,确保即使有瑕疵,产品的主干是可用的。
这是一个极端但可能发生的情况。我会这样做:
- 底线:必须有测试点:即使不写详细的用例,我也必须先快速地过一遍需求,用**思维导图(XMind)或清单(Checklist)**的形式,罗列出核心的测试点。这能保证我的测试不是盲目的,而是有依据、有覆盖度的。
- 执行探索性测试:基于梳理出的测试点,我会采用探索性测试的方法。凭借我的经验和对业务的理解,去模拟用户操作,重点关注主流程、关键分支和异常场景。
- 边测边记:在测试过程中,我会简单记录我测试过的路径和发现的问题。这既是为了避免重复测试,也是为了事后能追溯。
- 加强沟通:在这种情况下,与开发和产品的实时沟通变得至关重要。发现问题立刻沟通,确认问题立刻修复,快速迭代。
一个完整的测试计划通常包括:
- 项目背景:介绍项目目标和背景。
- 测试范围:明确本次测试要覆盖的功能模块和特性。
- 测试目标:定义测试要达到的质量标准。
- 测试策略:采用哪些测试方法和技术。
- 资源计划:需要的人员、硬件、软件资源。
- 进度安排:定义各个测试阶段的起止时间和里程碑。
- 风险评估与对策:识别潜在风险并制定应对计划。
- 人员分工:明确每个人的职责。
- 准入/准出标准:定义开始测试和结束测试的条件。
一个完整的测试报告通常包括:
- 测试摘要:总结本次测试的基本情况和核心结论。
- 测试范围:回顾本次测试覆盖了哪些内容。
- 测试环境:列出测试使用的软硬件环境。
- 测试执行情况:
- 执行了多少用例,通过率是多少。
- 发现了多少缺陷,按严重等级和状态进行统计分析。
- 缺陷分析:对缺陷的分布、趋势进行分析。
- 风险评估:列出当前版本遗留的已知问题和潜在风险。
- 质量评估与上线建议:对当前版本的整体质量给出一个综合评价,并明确给出“建议上线”、“不建议上线”或“有条件上线”的结论。
可以简单理解为:
- 测试计划 (Test Plan):是事前的规划,回答的是“我们要怎么测?”的问题。它是指导性的。
- 测试报告 (Test Report):是事后的总结,回答的是“我们测得怎么样?”的问题。它是结论性的。 一个是作战计划书,一个是战后总结报告。
写过。测试策略通常是测试计划中的一个核心章节,它详细说明了**“如何测”**的具体方法。内容包括:
- 测试层级:明确单元测试、接口测试、UI测试的投入比例和重点。
- 测试类型:确定本次需要进行的测试类型,如功能测试、性能测试、兼容性测试等,以及各自的测试重点。
- 自动化策略:定义哪些用例需要自动化,使用什么框架和工具。
- 测试数据策略:如何准备和管理测试数据。
- 环境策略:使用哪些测试环境,如何管理。
- 回归策略:定义回归测试的范围和执行时机。
不一定。发现的缺陷数量(Bugs Found)和软件中实际存在的缺陷数量(Bugs Present)不是一回事。
- 一方面,如果在一个简单的模块中,短时间内发现了大量严重Bug,这通常能说明该模块的开发质量很差,实际缺陷也很多。
- 另一方面,一个经验丰富、能力强的测试团队,可能会在一个中等质量的软件中,通过深入测试,发现比普通团队更多的隐藏较深的Bug。这时,“发现的缺陷多”反而体现了测试团队的价值。 因此,不能孤立地看这个数字,必须结合软件的复杂度、测试投入的深度、缺陷的严重等级分布、以及缺陷收敛的趋势来综合判断软件的真实质量。
我们有一套标准的线上问题应急流程(SOP):
- 问题上报与定级:由客服、运营或监控系统发现问题,第一时间上报到应急响应群。由技术负责人对问题的影响范围和严重性进行定级(P0-P4)。
- 信息同步与责任人:立即通知所有相关方(产品、开发、测试、运维),并明确该问题的总负责人(Owner)。
- 紧急止损:如果是严重问题,首要任务不是定位原因,而是恢复服务。可能的手段包括:回滚版本、服务降级、紧急扩容等。
- 问题定位与修复:在服务恢复或止损后,由开发和运维人员通过日志分析、监控数据等方式定位问题的根本原因,并开发修复补丁。
- 修复验证与上线:补丁开发完成后,由我们测试人员在预发布环境进行紧急验证,通过后立即上线。
- 复盘与总结 (Postmortem):问题彻底解决后,必须组织复盘会议,分析问题根源、改进流程,并制定预防措施,避免同类问题再次发生。
答案同问题1。
答案同问题1。
我会保持冷静和专业,按照以下步骤处理:
- 安抚与信息收集:首先,向客户表示歉意,感谢他提出问题,并请他详细描述一下Bug的现象和操作步骤,如果可能的话,请他截图或录屏。
- 初步判断与复现:根据客户的描述,我会在我的测试环境或生产环境尝试复现问题。同时快速判断这个Bug的严重性。
- 内外部沟通:
- 对内:我会立即将这个问题同步给我的上级和相关的开发人员,并按照公司的缺陷管理流程,创建一条线上Bug记录。
- 对外:我会告诉客户“我们已经收到您反馈的问题,正在紧急排查中,有进展会第一时间同步给您”,保持信息的通畅。
- 推动解决:我会积极配合开发定位问题,并在修复后第一时间进行验证。
- 闭环反馈:问题解决并上线后,我会告知客户问题已修复,并再次感谢他的反馈。
漏测是不可避免的,关键在于如何处理和总结。
- 紧急响应:首先,按照线上问题应急流程,优先恢复线上服务。
- 根本原因分析 (RCA):在问题解决后,我会进行深入的自我反思和复盘:
- 需求理解:是不是我当初对需求理解有偏差?
- 用例设计:是我的测试用例设计有遗漏,没有覆盖到这个场景吗?为什么会遗漏?是等价类划分不全,还是场景考虑不周?
- 测试执行:是用例设计了,但因为某些原因没有执行,或者执行时没有发现问题?
- 流程问题:是不是评审流程、回归策略存在漏洞?
- 改进与预防:
- 补充用例:将这次漏测的场景补充到我们的回归测试用例库中,防止未来再次发生。
- 流程优化:如果是流程问题,就推动优化团队的测试流程。比如,如果是需求不明确导致的,就建议以后需求评审需要有更详细的Checklist。
- 知识分享:将这次漏测的案例在团队内部进行分享,让大家共同学习,避免其他人犯同样的错误。
- 确认问题范围:首先判断是只有我一个人有问题,还是所有同事都遇到了问题。
- 初步自查:我会先检查是不是我本地配置、网络或操作的问题。
- 定位问题:如果排除是个人问题,我会尝试定位环境问题的根源。比如,是某个服务挂了?数据库连不上了?还是Nginx配置错了?我会通过
ping服务、查看服务进程、看日志等方式进行初步排查。 - 上报和求助:如果我无法解决,或者确定是环境的普遍性问题,我会立即在公司的技术支持群里上报问题,并**@相关的运维或开发**同学,清晰地描述问题现象和我的初步排查结果,请求他们协助解决。
- 跟进和通知:在问题解决前,我会持续跟进,并通知其他受影响的测试同事,避免大家做无用功。
这取决于Bug的发现时间和严重等级。
- 发版前(预发布验证阶段)发现:
- 严重Bug:立即中止发布流程,开发紧急修复,测试验证通过后,重新启动发布。
- 非严重Bug:快速评估其影响。如果影响小、用户感知弱,并且有临时解决方案,经过产品和项目经理同意,可以先发版,再发布一个补丁版本。否则,同样中止发布。
- 发版后(线上验证阶段)发现:
- 立即启动线上问题应急预案。
- 首选回滚:如果是严重问题,最快最稳妥的方式是立刻回滚到上一个稳定版本。
- 紧急修复:如果问题不严重但必须马上修复,且回滚影响更大,则开发紧急出Hotfix(热修复)版本,测试验证后,再次上线。
- 立即上报:第一时间报告给测试经理和项目经理,清晰说明Bug的现象和严重性。
- 评估影响:和产品、开发一起快速评估这个Bug对用户的影响范围、触发概率以及可能造成的损失。
- 决策:基于评估结果,项目决策层(通常是项目经理和产品负责人)会做出决定:
- 选项A:延迟上线 (Delay):如果Bug是致命或严重的,必须修复,那么推迟原定的上线时间。
- 选项B:带Bug上线 (Accept):如果Bug影响非常小,且修复成本和风险很高,可能会决定暂时接受它,并告知用户或客服。
- 选项C:剥离功能 (Remove):如果Bug只存在于某个次要的新功能中,可以考虑暂时屏蔽这个功能入口,保证主体版本按时上线。 我的角色是提供准确的Bug信息和风险评估,辅助管理层做出最明智的决策。
这是最糟糕的情况。处理原则是**“质量优先于速度”**。
- 坚决叫停:作为测试,我的职责是守住质量底线。我会坚决地提出**“不建议上线”**的意见,并以数据和事实说明该Bug可能带来的严重后果(比如用户资金损失、公司声誉受损)。
- 寻求替代方案:与团队一起探讨是否有临时的规避方案(Workaround)。比如,是否可以通过后台配置暂时关闭这个有问题的功能?是否可以引导用户使用其他方式完成操作?
- 准备用户沟通预案:如果最终不得不延迟上线,需要配合产品和运营,准备好对用户的安抚和解释文案。 绝不能为了赶时间,而将一个已知的、重大的“定时炸弹”发布到线上。
有的。我们有明确的发布决策流程和线上应急预案。
- 发布决策流程规定了,任何P0级别的Bug都必须在上线前修复,P1级别的Bug需要经过项目核心干系人评审同意后才能上线。
- 线上应急预案则定义了线上问题发生后的处理流程、责任人和沟通机制,确保一旦出问题,我们能最快地响应和恢复。
处理偶现Bug是对测试人员耐心和技术能力的极大考验。我的处理思路是:
- 第一时间详细记录:一旦遇到,我会立刻尽可能详细地记录下当时的所有信息:我的操作步骤、输入的数据、出现问题的时间点、前端的现象、后台日志的快照等等。哪怕只有一次,这些信息也至关重要。
- 尝试多种方式复现:
- 路径复现:严格按照记忆中的步骤,反复尝试。
- 环境复现:尝试更换网络、浏览器、账号,看是否与特定环境有关。
- 数据复现:分析当时的数据状态,尝试构造类似的数据来复现。
- 扩大信息收集范围:
- 查看更详细的日志:请求开发帮忙打开DEBUG级别的日志,或者查看更底层的系统日志、Nginx日志。
- 分析代码:如果有可能,我会请开发和我一起Code Review,分析可能出现问题的代码逻辑,比如多线程、异步处理、静态变量等地方。
- 与开发紧密合作:我会把所有收集到的信息都提供给开发,和他一起分析和推测可能的原因,并在他的指导下尝试一些更特殊的复现手法。
- 长期跟进:即使暂时无法复现和解决,我也会把这个Bug记录下来,并在后续的测试中持续关注。
排查思路:
- 由浅入深:先从应用层(操作、UI)排查,再到中间件层(Nginx, Tomcat),再到服务层(日志),最后到数据层(数据库, 缓存)。
- 排除法:逐一排除可能的原因,比如先排除是网络问题,再排除是浏览器问题等。
- 关联分析:分析Bug出现的时间点,与当时服务器的CPU、内存、并发量等监控指标进行关联,看是否有相关性。
- 代码分析:重点关注代码中的非幂等操作、线程安全问题、资源释放、异步回调处理等部分。
解决方案:
- 增加日志:最有效的方式是在可疑的代码块前后增加详细的日志打印,等到下次问题复现时,通过日志来定位。
- 压力测试:很多偶现问题是在高并发下才会暴露的,可以尝试对相关模块进行压力测试,提高复现概率。
- 代码评审:邀请多位有经验的开发人员一起对相关代码进行评审。
复现偶现Bug没有固定的方法,更像是一种“侦探工作”:
- 环境模拟:尽可能地还原Bug发生时的软硬件环境、网络状况。
- 数据构造:分析Bug发生时的数据特征,构造出高度相似的“脏数据”或边界数据。
- 并发模拟:使用JMeter等工具,模拟大量的并发用户,持续对问题接口进行访问。
- 操作序列模拟:有时候Bug是由一系列特定的操作顺序触发的,需要耐心尝试各种可能的操作组合。
- 代码插桩/增加日志:在无法复现的情况下,这通常是最后的、也是最有效的手段。
这是一个艰难的决策。
- 评估风险:我会和产品、开发一起,尽最大努力评估这个偶现Bug的触发概率和造成的影响。
- 影响:如果这个Bug会导致用户资金损失、数据丢失或系统崩溃,那么即使概率再低,它也是一个高危风险。
- 概率:如果这个Bug只是一个轻微的UI问题,且在我们长时间的测试中只出现过一两次,那么风险相对可控。
- 提供决策依据:我会将风险评估的结果,以书面形式记录在测试报告中,并向项目决策层清晰地阐述。
- 给出我的专业建议:
- 对于高危风险:我的建议是延迟上线,直到问题解决或找到明确的规避方案。
- 对于低危风险:我的建议是可以上线,但必须有预案。这个预案包括:加强线上监控,一旦发现问题立刻告警;准备好快速回滚或紧急修复的方案;提前告知客服和运营,如果收到用户反馈,应该如何应对。 最终的决定由管理层来做,但我的责任是把风险说清楚,并给出专业的建议。
有发生过意见不一致的情况,但没有升级为激烈的个人冲突。
最常见的原因是对一个Bug的定级或归属有分歧。比如,我认为一个问题是严重级别,应该在当前版本修复,但开发认为它影响不大,可以延后。或者一个Bug,前端开发认为是后端接口返回数据的问题,后端开发认为是前端没有正确处理数据。
之所以觉得棘手,是因为这不仅仅是一个技术问题,还考验沟通和协作能力。我的解决方法是摆事实、讲道理、求共识:
- 摆事实:我会当面给他复现一遍,并展示我的依据,比如需求文档的原文、相关的日志截图、接口返回的报文等,用客观事实说话。
- 讲道理:我会从用户的角度、从业务流程的角度,向他解释为什么这个Bug会影响用户体验,或者可能在哪些场景下引发更严重的问题。
- 求共识:如果我和开发还是无法达成一致,我会把产品经理请过来。我们三方一起讨论,最终由产品经理这个“需求提出者”来做最终裁决。这样就把“我和你的分歧”变成了“我们团队如何更好地实现产品需求”的共同目标。
- 提前预警:在开发周期的中段,我就会主动去了解开发的进度。如果发现有延期的风险,我会提前在项目例会上提出来,起到预警作用。
- 正式沟通:如果真的发生了延期,我会第一时间找到对应的开发和项目经理,了解延期的具体原因和预计新的提测时间。
- 影响分析:我会根据新的提测时间,重新评估测试所需的时间,并明确指出测试时间被压缩了多少,可能会带来哪些测试不充分的风险。
- 寻求解决方案:和项目经理、开发一起商量对策。方案可能是:开发加班赶进度、我们测试也做好加班准备、或者对本次上线的需求范围进行削减。关键是让问题暴露出来,大家一起想办法解决,而不是自己默默承受测试时间被压缩的后果。
越早解决越好。
- 在需求评审阶段:如果这时就发现理解不一致,是最好的情况。我们会立刻提出来,和产品经理、开发一起讨论,直到三方对需求的理解达成一致。
- 在测试设计/执行阶段:如果这时才发现,我会立刻停下手中的工作,找到开发和产品经理,把我理解的逻辑、开发实现的逻辑、以及需求文档的描述都摆出来,进行三方对齐。明确最终正确的逻辑后,再继续进行测试或要求开发进行修改。 核心原则是:任何时候,只要发现理解不一致,都要立刻沟通,并以产品经理的解释为最终标准。
- 评估影响:首先,我会快速评估这个新增需求的影响范围。它是一个独立的小功能,还是会嵌入到现有复杂流程中?它会影响哪些已有的模块?
- 评估工作量:基于影响评估,我会估算出测试这个新需求需要额外增加多少工作量,包括用例设计、执行和回归测试的时间。
- 沟通风险:我会拿着我的评估结果,去找项目经理和产品经理,向他们说明情况:要加这个需求可以,但这会导致原定的测试计划延期,或者需要对其他功能的测试范围进行缩减。
- 等待决策:由项目经理和产品经理来做决策,是推迟上线日期,还是放弃这个新增需求,或者削减其他需求来保证按时上线。 我的职责是提供准确的评估,让他们能做出明智的决策,而不是默默接受然后加班。
处理流程和临时加需求类似:
- 确认变更:确保这个变更是正式的、经过产品确认的,而不是某个人的口头提议。
- 影响分析:分析这个变更会影响到哪些模块的功能、代码和已有的测试用例。
- 更新文档:更新我的测试计划和测试用例,以匹配新的需求。
- 工作量评估与沟通:重新评估因此增加的测试工作量,并向项目经理汇报,看是否需要调整项目排期。
- 加强回归:对受影响的模块进行重点回归测试。
我需要做:确认变更 -> 分析影响 -> 更新用例 -> 重新评估工作量 -> 调整测试计划 -> 执行测试和回归。
这是一个流程管理问题,需要从团队层面解决。作为测试工程师,我可以:
- 记录和量化:记录下每次需求变更的时间、内容和对测试工作量的影响,用数据来证明“频繁变更”这个问题的严重性。
- 向上反馈:将这些数据反馈给我的测试经理和项目经理,建议项目组重视这个问题。
- 推动流程优化:建议团队建立更严格的需求变更控制流程。比如,规定在迭代开发开始后,任何非紧急的、重大的需求变更都不能接纳,必须放入下一个迭代。或者,建立一个变更评审委员会,对每个变更的必要性和成本进行评估。
属于。 从广义的缺陷定义来看,“软件未达到需求规格说明书中虽未指明但应达到的目标”也属于缺陷。需求不完整或存在逻辑漏洞,是源头上的缺陷。 在实际工作中,我们通常不会在缺陷管理系统里给产品经理提一个“需求Bug”。更常见的做法是,在需求评审阶段,或者在后续的测试设计阶段,一旦发现需求的问题,就立刻通过口头沟通、邮件或在需求管理工具(如Jira)中评论的方式,指出来并推动产品经理去完善。
- 立即暂停:暂停与该异议点相关的测试工作,避免做无用功。
- 记录和澄清:清晰地记录下我的疑问,以及我认为不合理的地方。
- 发起沟通:找到产品经理进行沟通,他是需求的最终解释者。如果需要,可以拉上开发一起,进行三方对齐。
- 等待确认:在产品经理给出明确的、书面的答复之前,不基于我的个人猜测去执行测试。
绝不靠猜。我会:
- 反复阅读:先自己多读几遍,看是否能从上下文和其他文档中找到答案。
- 列出问题清单:把我所有不理解的地方,整理成一个清晰的问题列表。
- 主动沟通:拿着我的问题清单,去找产品经理,逐一进行沟通确认。
- 邮件确认:对于一些关键的、重要的确认点,沟通完毕后,我会发一封会议纪要或者确认邮件,抄送给相关人员,留下书面记录,避免后续产生争议。
这里说的“Bug”,通常是指需求文档本身的逻辑漏洞或设计缺陷。 我的做法是:立即沟通。 我会马上找到产品经理,向他指出我发现的问题。比如,“这个地方的设计,在A场景下是合理的,但在B场景下可能会导致用户数据错乱,您看是不是这样?” 通过这种方式,可以在编码开始前就发现并修复问题,这是成本最低、效率最高的方式,也是测试“左移”价值的体现。
- 立即补充:一旦意识到有遗漏,我会马上把遗漏的测试点和对应的测试用例补充到我的测试用例库中。
- 执行测试:立即对补充的用例进行测试。
- 影响评估:评估这个遗漏点是否会影响到其他已经测试过的功能,如果有关联,需要对关联部分进行回归。
- 复盘:在事后,我会思考为什么当初会遗漏这个测试点,是需求理解不到位,还是用例设计方法使用不当,从中吸取教训,避免未来再犯。
- 保持冷静,做好记录:首先,有条不紊地将发现的每一个Bug都记录到缺陷管理系统中,确保信息完整、描述清晰。
- 分类和定级:对Bug进行分类(功能、UI等)和严重等级划分。
- 及时沟通与预警:当发现Bug数量异常增多,特别是严重Bug数量较多时,我会立即将这个情况同步给测试经理和项目经理。这通常是提测版本质量差的明确信号。
- 建议打回:如果Bug多到已经阻塞了主要流程的测试,我会建议中止本次测试,将版本打回,要求开发进行更充分的自测后再重新提测。这比我们继续在糟糕的版本上浪费时间更有效率。
- 协助定位:对于已提交的Bug,我会积极配合开发进行定位,帮助他们尽快修复。
我认为测试工作中的主要难点有三个:
- 需求的复杂性和易变性:这是最大的挑战。应对方法是:尽早和持续地参与到需求讨论中,通过评审、沟通等方式,将自己对业务的理解保持与团队同步,并推动建立合理的需求变更流程。
- 偶现问题的定位:非常耗时且考验技术能力。应对方法是:耐心、细致,多方收集信息(日志、监控),并与开发紧密协作,运用逻辑推理和技术手段逐步缩小范围。
- 测试时间的压缩:这是最常见的困境。应对方法是:通过风险评估和优先级排序,在有限的时间内做最重要的事情。同时积极沟通,让整个团队都意识到风险,共同承担和解决问题,而不是让测试成为唯一的“背锅侠”。
1.复现异常情况:能复现VS不能复现。
能复现:把出现异常的情况描述给开发。
不能复现:进一步排查问题(外部原因VS内部原因);
外部原因:网络、设备、...
内部原因:查日志、...
2.查日志:有错误或异常VS没有错误或异常
没有错误或异常:另想他法...
有错误或异常:把报错的内容提交给开发。
- 如何完成报错的内容提交给开发?
有错误或者异常VS没有错误或异常
没有错误或异常:另想他法....
有错误或者异常:把报错的前后10行内容重定向到bug.txt文件中
4.通过Xftp把Linux中的bug.txt文件下载到自己电脑上
5.把bug.txt文件提交给开发。
我工作中常用的Linux命令主要分为几类:
-
文件/目录操作:
ls(列出目录),cd(切换目录),pwd(显示当前路径),mkdir(创建目录),touch(创建文件),rm(删除),cp(复制),mv(移动/重命名)。 -
文件内容查看:
cat(查看全部内容),more(分页查看),less(可上下翻页查看),head(查看头部内容),tail(查看尾部内容)。 -
内容搜索/过滤:
grep(文本搜索),find(文件查找)。 -
进程管理:
ps(查看进程),top(动态查看进程),kill(结束进程)。 -
系统/资源:
df(查看磁盘空间),free(查看内存),netstat(查看网络端口)。 -
压缩/解压:
tar。 -
权限管理:
chmod。我的:
查看类:
目录:mkdir 创建目录**,ls**(列出目录内容)、ll(ls -l 的别名,详细列出)、cd(切换目录)、pwd(显示当前路径)
文件:touch 创建文件**,rm -rf删除文件,rmdir** 删除空目录
cat(查看文件内容)、more(分页查看)、less(分页可回退查看)、head(查看文件头部)、tail(查看文件尾部,-f 实时跟踪)
磁盘:df(查看磁盘空间使用情况,-h 人性化显示)、du(查看目录 / 文件磁盘占用
内存:free(查看内存使用,-h 人性化)、top(动态查看内存和进程)
文件大小du -h 目录/文件 查看某个目录/文件的大小。
进程**:ps**(查看进程,aux 参数显示所有进程)、top(动态进程信息)
服务:service 服务名 status
端口:lsof -i: 端口号(查看端口占用),netstat -anp 查看所有端口号信息。Ss -anp
查找类:find 路径 -name 文件名(按名称查找)
grep 关键词 文件名(在文件中查找关键词)
压缩/解压:tar -zcvf 压缩包.tar.gz 目录 / 文件(压缩)
tar -zxvf 压缩包.tar.gz(解压)
zip 压缩包.zip 目录 / 文件(压缩)
unzip 压缩包.zip(解压)
修改文件权限:字母法:chmod [u/g/o/a][+/-/=][r/w/x] 文件名(u 用户,g 组,o 其他,a 所有;+ 添加,- 移除,= 设置;r 读,w 写,x 执行)
数字法:chmod 三位数字 文件名(r=4,w=2,x=1,三位分别代表 u/g/o,如 755 即 rwxr-xr-x)
我们公司的服务器主要用的是 CentOS,版本是 7.x。
在我的测试工作中,Linux主要用来做三件事:
-
查看服务日志:当功能出现问题时,我会登录到服务器,进入应用的日志目录,使用
tail、grep等命令来查看实时的报错信息,这是定位后端Bug最主要的方式。 -
检查服务状态:有时候环境出问题,我会用
ps -ef | grep java来检查我们的Java应用进程是否还在运行。 -
部署和环境维护:虽然主要是运维负责,但有时我也会在测试环境上拉取最新的代码,或者修改一些配置文件,然后重启服务来验证一个紧急的Bug修复。
定位BUG(如:查日志,查端口,查进程,查服务,...)
几乎每天都会用到。只要是需要排查后端问题、确认服务状态、或者查看任何与服务器相关的信息时,我都需要登录Linux系统进行操作。
在测试环境,我们有普通用户的登录权限,并且通过 sudo 可以执行一些需要更高权限的操作,比如重启服务。但是在预发布环境和生产环境,我们只有只读权限,不能进行任何修改操作,以保证环境的稳定和安全。
- 绝对路径 (Absolute Path):路径的写法从根目录
/开始,它是一个完整的、唯一的路径。例如:/usr/local/tomcat/logs。 - 相对路径 (Relative Path):路径的写法不从根目录
/开始,而是以当前所在目录为参照点。例如,如果我当前在/usr/local/tomcat目录下,那么logs就是一个相对路径,它等同于绝对路径/usr/local/tomcat/logs。相对路径中.代表当前目录,..代表上一级目录。
使用 ps 命令。最常用的组合是 ps -ef 或者 ps aux,它们可以列出当前系统所有的进程。通常我会配合 grep 来查找特定的进程,例如:
ps -ef | grep tomcat
使用 top 命令。top 命令可以实时、动态地显示系统中各个进程的资源占用状况,比如CPU、内存的使用率,并且默认按CPU使用率排序。
它们显示的内容和风格略有不同,但达成的效果是类似的,都是显示所有进程的详细信息。
ps -ef是 System V 风格的命令,显示信息中包含UID,PID,PPID(父进程ID),C(CPU占用),STIME(启动时间),TTY(终端),TIME(CPU占用时间),CMD(命令)。ps aux是 BSD 风格的命令,显示信息中包含USER,PID,%CPU,%MEM,VSZ(虚拟内存),RSS(物理内存),STAT(状态),START,TIME,COMMAND。 在日常使用中,选择哪个主要看个人习惯,我个人更习惯用ps -ef。
top 命令是一个动态的进程监视器。它能实时显示系统中各个进程的资源占用情况,如CPU使用率、内存使用率、进程ID等,并按CPU使用率从高到低排序。通过 top 命令,我们可以快速找出是哪个进程占用了大量的系统资源,是性能分析和问题排查的重要工具。
最直接的方法是:
ps -ef | grep java
或者,如果知道应用的具体名称,可以:
ps -ef | grep my-application.jar
使用 kill 命令。首先需要通过 ps 命令找到要杀死的进程的PID(进程ID)。然后执行:
kill [PID]
这个命令会向进程发送一个TERM信号,尝试正常终止它。如果进程无法正常终止,可以使用 -9 选项来强制杀死:
kill -9 [PID]
这是一个非常强硬的操作,只有在必要时才使用。
首先,用 ps -ef | grep [进程名] 找到进程的PID。例如,找到tomcat的PID是 12345。
然后,执行 kill 12345 来尝试正常关闭它。
如果几秒后,再次用 ps 命令查看,发现进程还在,那就执行 kill -9 12345 来强制杀死它。
使用 netstat 命令:
netstat -anp | grep [端口号]
例如,查看 8080 端口是否被占用:
netstat -anp | grep 8080
如果该端口被占用,命令会输出相关的信息,包括占用该端口的进程PID。
这个问题可能有点歧义。
- 如果是指一个进程打开了哪些文件,占用了哪些文件句柄,可以用
lsof -p [PID]。 - 如果是指一个进程产生的日志或其他文件占用了多少磁盘空间,那就需要先找到这些文件,然后用
du -sh [文件名或目录]来查看。
使用 df 命令。常用的参数是 -h,它可以以人类可读的格式(如G、M)显示磁盘空间。
df -h
这个命令会列出所有文件系统的总容量、已用空间、可用空间和挂载点。
- 综合实时查看:使用
top命令,可以实时看到CPU、内存的总体占用率,以及各个进程的资源消耗情况。 - 查看内存:使用
free -h,可以清晰地看到总内存、已用、可用、缓存等信息。 - 查看CPU:除了
top,还可以查看/proc/cpuinfo文件来获取CPU的详细信息,如型号、核心数等。 - 查看磁盘:使用
df -h查看磁盘分区使用情况,使用du -sh [目录]查看指定目录的大小。
cat /proc/cpuinfo
这个命令会输出CPU的详细硬件信息,包括型号(model name)、核心数(cpu cores)、线程数(siblings)等。
这取决于服务的管理方式。
- 使用脚本:规范部署的服务通常都有启动/停止脚本。例如,重启tomcat可能就是执行:
./shutdown.sh./startup.sh或者一个集成的重启脚本./restart.sh。 - 使用 systemd (CentOS 7及以后):
systemctl restart [服务名]还有一个旧版本的service 服务名 restart 例如:systemctl restart nginx。 - 手动重启:如果没有任何管理工具,那就只能先用
ps找到PID,kill掉进程,然后再手动执行启动命令。
与重启类似:
- 使用脚本:
./shutdown.sh - 使用 systemd:
systemctl stop [服务名],还有一个旧版本的service 服务名 stop - 手动停止:
kill [PID]
主要使用 cat, more, less, head, tail, grep 这些命令的组合。
- 查看小文件:
cat catalina.out - 分页查看大文件:
less catalina.out(推荐,功能比more强) - 查看文件开头:
head -n 200 catalina.out(查看前200行) - 查看文件结尾:
tail -n 200 catalina.out(查看后200行)
cat, more, less, head, tail, grep。
cat:一次性显示文件的所有内容。适合小文件。more:分页显示文件内容,只能向下翻页。less:more的增强版,分页显示,可以自由地上下翻页,还可以进行搜索。是查看大日志文件的首选。head:只显示文件开头的几行(默认10行)。tail:只显示文件末尾的几行(默认10行)。最常用的是tail -f。
使用 tail -f 命令。它会持续监控文件的末尾,一旦有新内容追加进来,就会立刻显示在屏幕上。这对于观察正在运行的应用的实时日志输出非常有用。
tail -f application.log
如果要同时看实时日志并过滤关键字,可以这样:
tail -f application.log | grep ERROR
- 首先
cd到项目的日志目录下。 - 用
ls -lrt命令按修改时间倒序排列文件,最后面的那个通常就是最新的日志文件。 - 用
tail -n 500 [最新日志文件名]查看最后500行内容。 - 或者直接用
tail -f [最新日志文件名]来实时查看。
head -n 100 [文件名]
或者
head -100 [文件名]
tail -n 100 [文件名]
或者
tail -100 [文件名]
这个问题有点模糊,通常“后100行”就是最新的内容。
- 如果是指静态查看最后100行,就是
tail -100 [文件名]。 - 如果是指持续查看最新的内容,就是
tail -f [文件名]。
使用 grep 命令。grep 可以从文本流中过滤出包含指定字符串的行。
grep -i 'ERROR' application.log
或者,更常用的是和 cat 或 tail 配合使用:
cat application.log | grep 'ERROR'
tail -1000f application.log | grep 'ERROR' (实时查看最近1000行中的错误)
这需要根据日志的格式来定,假设日志每行开头都有 YYYY-MM-DD HH:MM:SS 格式的时间戳。
可以使用 grep 的正则表达式功能,或者 sed、awk 等更强大的工具。
一个简单的 grep 示例:
grep '2025-11-10 21:' application.log.2025-11-10 (查看21点的所有日志)
grep '2025-11-10 22:' application.log.2025-11-10 (查看22点的所有日志)
如果要精确匹配,可以用 sed:
sed -n '/2025-11-10 21:00:00/,/2025-11-10 23:00:00/p' application.log
这个命令会打印出从晚上9点到11点之间的所有日志行。
答案同问题30,使用 sed 或 awk 是最精确的方式。
sed -n '/起始时间/,/结束时间/p' [文件名]
使用 grep 的上下文查看参数:
-A(After): 显示匹配行之后的N行。-B(Before): 显示匹配行之前的N行。-C(Context): 显示匹配行前后各N行。
所以,查看报错的前后10行内容,命令是:
grep -i -C 10 'ERROR' application.log
使用 touch 命令。如果文件不存在,它会创建一个空文件;如果文件已存在,它会更新文件的修改时间。
touch new_file.txt
使用 mkdir 命令。
mkdir new_directory
如果需要创建多级目录,比如 a/b/c,可以使用 -p 参数:
mkdir -p a/b/c
不用。touch 是用来创建文件的。创建目录必须用 mkdir。
- 命令不同:创建目录用
mkdir,创建文件用touch。 - 本质不同:目录是一个特殊的文件,它包含了其他文件和目录的列表。而普通文件是用来存储数据的。在文件系统中,它们的类型是不同的。
使用 rm 命令。
rm file.txt
如果要删除一个目录,需要加上 -r (recursive) 参数:
rm -r directory
如果要强制删除且不提示,可以加上 -f (force) 参数:
rm -rf directory (这是一个非常危险的命令,使用时要格外小心!)
使用 mv 命令。mv 命令有两个功能:移动文件/目录,以及重命名文件/目录。
- 移动:
mv /path/to/source_file /path/to/destination_directory - 重命名:
mv old_name.txt new_name.txt(在同一目录下)
pwd (Print Working Directory)。
这个题目应该是 ls 和 ls -a 的区别。
ls:列出当前目录下的文件和目录,但不包括以.开头的隐藏文件。ls -a:列出当前目录下的所有文件和目录,包括隐藏文件(如.bashrc)以及.(当前目录) 和..(上级目录)。
主要用 find 命令。find 命令功能非常强大,可以根据文件名、大小、修改时间等多种条件来查找。
基本用法是:
find [查找路径] -name "[文件名]"
例如,在当前目录下查找所有名为 test.log 的文件:
find . -name "test.log"
- find:
- 工作方式:实时地、地毯式地搜索硬盘。
- 优点:查找结果是实时的、最准确的。
- 缺点:如果目录很大,搜索速度会很慢。
- locate:
- 工作方式:不是实时搜索,而是去搜索一个事先创建好的数据库 (
mlocate.db)。 - 优点:速度极快,几乎是瞬间出结果。
- 缺点:查找结果不是实时的。如果一个文件是刚创建的,数据库还没来得及更新(通常每天更新一次),
locate就找不到它。
- 工作方式:不是实时搜索,而是去搜索一个事先创建好的数据库 (
- 查看单个文件大小:
ls -lh [文件名]或者du -sh [文件名] - 找出最大的文件:
可以组合使用
find,du,sort,head命令。一个常用的方法是:find . -type f -print0 | xargs -0 du -h | sort -rh | head -n 10这个命令会找出当前目录下最大的10个文件。 - du -h * |sort -n | tail -n 11对当前目录下所有文件从降序显示。
使用 chmod 命令和数字表示法。
- 读 (r) = 4
- 写 (w) = 2
- 执行 (x) = 1
“所有人”分为三类:文件所有者 (User)、所属组 (Group)、其他人 (Others)。
可读可写可执行的权限值是 4 + 2 + 1 = 7。
所以,给所有人rwx权限的命令是:
chmod 777 filename
chmod 主要有两种使用方式:
- 数字模式:
chmod [三位数字] [文件名]。如chmod 755 script.sh,表示所有者有读写执行权限(7),所属组和其他人有读和执行权限(5)。 - 符号模式:
chmod [ugoa][+-=][rwx] [文件名]。u,g,o,a分别代表 user, group, others, all。+, -, =分别代表增加、移除、设置权限。r,w,x代表读、写、执行。 例如:chmod u+x script.sh(给文件所有者增加执行权限)。
使用 ls -l 命令。
输出结果的第一列就是文件类型和权限信息,例如 -rwxr-xr--。
- 第一个
-表示这是一个普通文件(如果是d则表示目录)。 - 后面九个字符,每三个一组,分别代表所有者、所属组、其他人的**读(r)、写(w)、执行(x)**权限。
修改文件权限用 chmod 命令。
权限数字 652 的意思是:
- 6 (rw-):
4+2=6,代表文件所有者有读、写权限,没有执行权限。 - 5 (r-x):
4+1=5,代表文件所属组有读、执行权限,没有写权限。 - 2 (-w-):
2,代表其他人只有写权限,没有读和执行权限。 所以,chmod 652 filename就是设置上述权限。
使用符号模式的 +x。
- 给所有人追加执行权限:
chmod a+x filename - 只给所有者追加执行权限:
chmod u+x filename
使用符号模式的 +w。
- 给所属组追加写权限:
chmod g+w filename
chmod u+x [文件名]
使用 ln -s 命令。软链接(Symbolic Link)类似于Windows的快捷方式。
语法是:ln -s [源文件或目录] [链接名]
例如:ln -s /usr/local/java/jdk1.8.0 /usr/bin/java
使用 tar 命令。常用的参数是 zcvf。
z: 通过 gzip 进行压缩。c: 创建一个新的 tar 包。v: 显示详细过程。f: 指定文件名。 语法:tar zcvf [压缩后的文件名.tar.gz] [要压缩的文件或目录]例如:tar zcvf logs.tar.gz ./logs
解压缩的命令是 tar zxvf logs.tar.gz (x 代表 extract)。
主要有三种模式:
- 命令模式 (Command Mode):刚进入vi/vim时的默认模式。在这个模式下,可以移动光标、删除文本、复制粘贴等,但不能直接输入文本。
- 插入模式 (Insert Mode):在命令模式下,按
i,a,o等键可以进入插入模式。在这个模式下,可以像记事本一样输入文本。按Esc键可以返回到命令模式。 - 底线命令模式 (Last Line Mode):在命令模式下,按
:键可以进入底线命令模式。在这个模式下,可以输入一些高级命令,如保存文件 (:w)、退出 (:q)、搜索 (:/pattern)、替换 (:%s/old/new/g) 等。
在vi/vim的底线命令模式下,使用 :s 命令。
语法::[范围]s/[查找的字符串]/[替换的字符串]/[标志]
- 替换当前行的第一个匹配项:
:s/old/new - 替换当前行的所有匹配项:
:s/old/new/g - 替换所有行的所有匹配项:
:%s/old/new/g
我们公司主要使用的是 MySQL。
我们生产环境用的是 MySQL 5.7 版本。这个版本稳定,社区支持好,性能也满足我们当前的业务需求。
我工作中主要使用 Navicat 这个图形化客户端工具来连接和管理数据库。它界面直观,功能强大,可以很方便地执行SQL查询、查看表结构、导入导出数据等。
数据库的核心作用是持久化地、结构化地存储和管理数据。 它解决了数据的高效增、删、改、查 (CRUD) 的问题,并确保了数据的安全性、一致性和共享性。
在我的测试工作中,数据库主要用于以下三个方面:
- 测试数据准备 ( 造数据 ):在测试开始前,通过
INSERT语句向数据库中插入特定状态的测试数据,以满足我的测试场景需要。 - 数据校验 ( 查数据 ):在前端或接口执行完一个操作后,通过
SELECT语句去数据库中查询相关表的数据,验证操作是否成功,数据是否正确地被创建、更新或删除了。这是判断后端逻辑是否正确的最终依据。 - 环境清理 ( 删数据 ):测试结束后,通过
DELETE或TRUNCATE语句清理掉测试产生的数据,以便下一次测试。
- 场景一:验证用户注册
- 操作:在前端页面注册一个新用户。
- 数据库验证:去
user表里SELECT * FROM user WHERE username='新注册的用户名';,看是否能查到这条新纪录,并且各个字段的值是否正确。
- 场景二:验证下单功能
- 操作:在App上下一个订单。
- 数据库验证:去
order表里查是否有新生成的订单记录;去order_item表里查订单里的商品是否正确;去stock表里查对应商品的库存是否被扣减。
- 场景三:准备退款测试数据
- 操作:在测试退款流程前,我需要一个“已支付”状态的订单。我可以直接通过
INSERT语句,或者UPDATE一个已有订单的状态,来快速构造出这个前置条件。
- 操作:在测试退款流程前,我需要一个“已支付”状态的订单。我可以直接通过
常见的关系型数据库有:
- MySQL (最流行的开源数据库)
- Oracle (功能强大的商业数据库)
- SQL Server (微软公司的数据库)
- PostgreSQL (功能非常强大的开源数据库)
- SQLite (轻量级的嵌入式数据库)
非关系型数据库(NoSQL)主要有四类:
- 键值(Key-Value)存储:Redis, Memcached
- 文档(Document)存储:MongoDB, CouchDB
- 列(Column-family)存储:HBase, Cassandra
- 图形(Graph)存储:Neo4j
事务的特性通常被称为 ACID 特性。
- A - 原子性 (Atomicity):事务是一个不可分割的工作单元,事务中的所有操作要么全部成功,要么全部失败回滚。
- C - 一致性 (Consistency):事务执行前后,数据库都必须处于一种合法的、一致的状态。比如转账,A账户减的钱必须等于B账户加的钱。
- I - 隔离性 (Isolation):多个并发事务之间是相互隔离的,一个事务的执行不应被其他事务干扰。
- D - 持久性 (Durability):一个事务一旦提交,它对数据库中数据的改变就是永久性的,即使系统崩溃也不会丢失。
视图(View)是一个虚拟表,它本身不存储数据,其内容由一个SQL查询语句定义。它的主要作用有:
- 简化复杂的SQL查询:可以将一个复杂的、多表连接的查询,定义成一个视图。之后查询这个视图,就像查询一个单表一样简单。
- 提高数据安全性:可以通过视图,只向用户暴露表中某些特定的列或行,隐藏敏感数据,从而实现更精细的权限控制。
- 提供数据独立性:当底层的表结构发生变化时,如果视图的定义不受影响,那么基于该视图的应用程序就无需修改。
| 特性 | 表 (Table) | 视图 (View) |
|---|---|---|
| 数据存储 | 真实地存储数据,占用物理空间 | 不存储数据,只是一个查询的定义,是虚拟的 |
| 本质 | 数据库中的基本数据结构 | 基于表或其他视图的查询结果 |
| 操作 | 可以进行增、删、改、查 | 通常主要用于查询,对视图的增删改会有限制 |
| 依赖关系 | 独立存在 | 依赖于其定义的基表 |
从逻辑上分,主要有四种:
- 主键索引 (Primary Key):一种特殊的唯一索引,不允许有空值,一张表只能有一个主键。
- 唯一索引 (Unique Key):索引列的值必须唯一,但允许有空值。
- 普通索引 (Normal/Index):最基本的索引,没有任何限制。
- 全文索引 (Full-text):用于对文本内容进行分词搜索,主要用于MyISAM和InnoDB(新版)引擎。
从物理存储(数据结构)上分,主要是 B+Tree 索引 和 哈希索引。
索引(Index)就像是书的目录,它的核心作用是提高数据库的查询速度。 如果没有索引,查询数据时MySQL需要遍历整张表(全表扫描)。而有了索引,MySQL可以通过B+Tree等数据结构,快速定位到数据所在的物理位置,大大减少了查询所需的时间,特别是对于数据量大的表。 当然,索引也有缺点:它会占用额外的磁盘空间,并且在对数据进行增、删、改时,需要额外的时间来维护索引,所以会降低写的性能。
即使建立了索引,在某些情况下SQL查询也不会使用索引,这就是索引失效。常见的原因有:
- 未使用最左前缀原则:对于联合索引(比如在
(a, b, c)列上建了索引),如果查询条件没有从索引的最左边的列开始(比如直接WHERE b = 1),索引会失效。 - 在索引列上进行运算或使用函数:比如
WHERE age - 1 = 20或WHERE SUBSTRING(name, 1, 1) = '张'。 - 使用
LIKE查询时,以%开头:比如WHERE name LIKE '%明'。 - 使用
OR连接条件,且OR前后的条件中有一个没有索引。 - 数据类型不匹配:比如列是字符串类型,但查询时用了数字
WHERE phone = 123456(应该是phone = '123456')。 - 查询优化器认为全表扫描更快:当表的数据量很小,或者查询需要返回大部分数据时,MySQL的查询优化器可能会认为直接全表扫描比走索引成本更低。
- 内连接 (INNER JOIN):只返回两张表中连接字段能够匹配上的行。如果一张表中的某行在另一张表中没有匹配的行,那么这行就不会出现在结果中。
- 外连接 (OUTER JOIN):除了返回两张表中能匹配上的行之外,还会返回某一张表中不匹配的行,不匹配的字段用
NULL补全。
它们是外连接的两种类型,区别在于以哪张表为准:
- 左外连接 (LEFT JOIN):以左边的表为基准。返回左表的所有行,以及右表中能匹配上的行。如果右表中没有匹配的,则右表的字段为
NULL。 - 右外连接 (RIGHT JOIN):以右边的表为基准。返回右表的所有行,以及左表中能匹配上的行。如果左表中没有匹配的,则左表的字段为
NULL。 在实际使用中,LEFT JOIN的使用频率远高于RIGHT JOIN,因为任何RIGHT JOIN都可以通过交换表的位置改写成LEFT JOIN。
WHERE 和 HAVING 都是用来筛选数据的,但它们的作用阶段和对象不同:
| 特性 | WHERE 子句 | HAVING 子句 |
|---|---|---|
| 作用阶段 | 在分组(GROUP BY)和聚合函数之前进行筛选 |
在分组和聚合函数之后进行筛选 |
| 作用对象 | 作用于原始表的行数据 | 作用于 GROUP BY 之后形成的分组结果 |
| 使用函数 | 不能使用聚合函数(如 COUNT(), SUM()) |
可以使用聚合函数 |
简单说:WHERE 筛选行,HAVING 筛选组。
- DDL (Data Definition Language) - 数据定义语言:
- 作用:用来定义和管理数据库的结构,比如数据库、表、索引等。
- 关键字:
CREATE(创建),ALTER(修改),DROP(删除),TRUNCATE(清空)。
- DML (Data Manipulation Language) - 数据操作语言:
- 作用:用来操作数据库表中的数据。
- 关键字:
INSERT(插入),UPDATE(更新),DELETE(删除)。 - 广义上,
SELECT(查询) 有时也被归入DML。
一个包含所有主要子句的 SELECT 语句,其逻辑上的执行顺序是:
FROM:确定要查询的表。ON:执行多表连接。JOIN:根据连接类型(INNER, LEFT)生成临时表。WHERE:对临时表的行进行筛选。GROUP BY:对筛选后的结果进行分组。HAVING:对分组后的结果进行筛选。SELECT:选取要显示的列(或进行计算)。DISTINCT:对结果进行去重。ORDER BY:对最终结果进行排序。LIMIT:对结果进行分页。
存储过程(Stored Procedure)是一组为了完成特定功能的、预先编译好的SQL语句集合。它被创建并存储在数据库中,可以由应用程序调用执行。 优点:
- 提高性能:预先编译,减少了网络传输和SQL解析的开销。
- 代码复用:可以将复杂的业务逻辑封装起来,供多个应用调用。
- 增强安全性:可以授予用户执行存储过程的权限,而不是直接操作表的权限。
E-R模型,也叫实体-关系模型 (Entity-Relationship Model),是用来描述现实世界概念模型的一种方法。它主要由三个核心要素构成:
- 实体 (Entity):指现实世界中客观存在的、可以相互区分的事物,比如一个“学生”、一件“商品”。在数据库中通常对应一张表。
- 属性 (Attribute):实体所具有的特征,比如“学生”有“学号”、“姓名”等属性。在数据库中通常对应表中的列(字段)。
- 关系 (Relationship):实体之间的联系。比如“学生”和“课程”之间存在“选修”的关系。关系有一对一、一对多、多对多三种类型。在数据库中通常通过外键来体现。
主要分为三类:
- 数值类型:
- 整数:
TINYINT,SMALLINT,INT,BIGINT - 小数:
FLOAT,DOUBLE(浮点数),DECIMAL(定点数,用于精确计算如金额)
- 整数:
- 字符串类型:
CHAR(定长字符串)VARCHAR(可变长字符串)TEXT,BLOB(用于存储长文本或二进制数据)
- 日期和时间类型:
DATE(日期)TIME(时间)DATETIME,TIMESTAMP(日期和时间)YEAR(年份)
| 特性 | CHAR | VARCHAR |
|---|---|---|
| 长度 | 定长。CHAR(10) 无论存多少字符,都占用10个字符的空间。 |
可变长。VARCHAR(10) 存3个字符就只占用3个字符+长度信息的空间。 |
| 性能 | 存取速度快,因为长度固定,无需计算。 | 存取速度相对慢,因为长度可变。 |
| 空间 | 可能浪费空间(存入的字符串短于定义长度时)。 | 节省空间。 |
| 适用场景 | 存储长度固定的数据,如手机号、MD5哈希值。 | 存储长度不固定的数据,如用户名、地址。 |
DECIMAL 是一种定点数类型,用于需要进行精确计算的场景,最典型的就是金额。
与 FLOAT 和 DOUBLE 这类浮点数不同,DECIMAL 是以字符串的形式来存储的,可以精确地表示小数,不会出现浮点数那样的精度丢失问题。
MySQL 主要有六大约束:
- 主键约束 (PRIMARY KEY)
- 唯一约束 (UNIQUE)
- 非空约束 (NOT NULL)
- 默认约束 (DEFAULT)
- 外键约束 (FOREIGN KEY)
- 检查约束 (CHECK) (MySQL 8.0.16 之后才真正支持)
答案同问题26。
约束(Constraint)是施加在表的数据列上的一种规则或强制。它的核心作用是保证数据库中数据的完整性、准确性和一致性。 例如,非空约束保证了某个字段必须有值;唯一约束保证了该字段的值不重复;外键约束保证了关联表之间的引用关系是正确的。
| 特性 | 主键 (Primary Key) | 唯一键 (Unique Key) | 外键 (Foreign Key) |
|---|---|---|---|
| 作用 | 唯一标识表中的一行数据 | 保证列中的值唯一不重复 | 建立两张表之间的关联关系 |
| 唯一性 | 必须唯一 | 必须唯一 | 可以不唯一 |
| 空值 | 不允许有 NULL 值 | 允许有 NULL 值(但通常只允许有一个) | 允许有 NULL 值 |
| 数量 | 一张表只能有一个主键 | 一张表可以有多个唯一键 | 一张表可以有多个外键 |
| 关联 | - | - | 必须引用另一张表的主键或唯一键 |
外键(Foreign Key)的核心作用是维护两张表之间的引用完整性。
它通过将一张表(从表)的某个字段与另一张表(主表)的主键或唯一键进行关联,来确保从表中的这个字段的值,必须在主表的关联字段中存在。
举例:在订单项表 order_item 中,order_id 字段可以设置为外键,引用订单主表 order 的主键 id。这样就保证了不可能凭空创建一个不属于任何订单的订单项,维护了数据的逻辑一致性。
聚合函数(Aggregate Functions)是对一组值进行计算,并返回单个值的函数。常用的有:
COUNT():统计行数。SUM():求和。AVG():计算平均值。MAX():找出最大值。MIN():找出最小值。
聚合函数通常与 GROUP BY 子句一起使用,用于进行分类汇总统计。
COUNT():统计每个部门的员工人数、每个班级的学生人数。SUM():计算每个销售区域的总销售额。AVG():计算每个学科的平均分。MAX()/MIN():找出每个部门中工资最高和最低的员工。
COUNT(*)或COUNT(1):统计表中的总行数,不关心任何列的值,效率最高。COUNT(字段名):统计指定字段非NULL值的行数。也就是说,如果某行的这个字段是NULL,那么这一行不会被计数。
SQL函数可以分为几大类:
- 聚合函数:
COUNT(),SUM(),AVG(),MAX(),MIN()。 - 字符串函数:
CONCAT()(拼接),LENGTH()(长度),SUBSTRING()(截取),UPPER()(转大写),LOWER()(转小写)。 - 数值函数:
ABS()(绝对值),ROUND()(四舍五入),CEIL()(向上取整),FLOOR()(向下取整)。 - 日期和时间函数:
NOW()(当前日期时间),CURDATE()(当前日期),YEAR()(获取年份),DATEDIFF()(计算日期差)。 - 流程控制函数:
IF(),CASE...WHEN...END。
当需要对数据进行分类汇总时,就需要使用分组 (GROUP BY)。
比如,当你的需求中出现了“每个...”、“每类...”这样的字眼时,通常就是要用 GROUP BY 了。
- 统计每个部门的人数。
- 计算每个商品分类的平均价格。
- 找出每个作者发表的文章数量。
这个问题比较宽泛,如果是指SQL关键字的话,常用的有:
- 查询:
SELECT,FROM,WHERE,GROUP BY,HAVING,ORDER BY,LIMIT - 连接:
INNER JOIN,LEFT JOIN - 修改:
INSERT INTO,UPDATE,DELETE FROM - 定义:
CREATE,ALTER,DROP - 其他:
DISTINCT,AS,AND,OR,NOT,IN,BETWEEN
DISTINCT。
SELECT DISTINCT column_name FROM table_name;
GROUP BY。
ORDER BY。
- 正序(升序):
ASC(Ascending)。这是默认的排序方式,可以省略不写。 - 倒序(降序):
DESC(Descending)。
BETWEEN ... AND ...。
WHERE age BETWEEN 18 AND 30; (包含18和30)
LIKE。它通常与通配符一起使用:
%(百分号):代表零个、一个或多个字符。_(下划线):代表一个单一字符。
在LIKE子句中,使用 _ (下划线)作为单个字符的通配符。
例如, WHERE name LIKE '张_' 可以匹配到“张三”,但匹配不到“张三丰”。
AND。
WHERE gender = '男' AND age > 20;
OR。
WHERE city = '北京' OR city = '上海';
LIMIT 后面跟两个数字,如 LIMIT m, n:
m:代表偏移量 (offset),即从第几条记录开始。注意:第一条记录的偏移量是0。所以,LIMIT 5, 10是指从第6条记录开始。n:代表要返回的记录数量 (count)。 总结:LIMIT m, n的意思是,跳过m条记录,然后取出n条记录。
主要通过 LIMIT 子句实现。分页查询需要两个参数:当前页码 (page_num) 和 每页大小 (page_size)。
SQL语句的 LIMIT 部分可以这样计算:
LIMIT (page_num - 1) * page_size, page_size
例如,每页显示10条,要查询第3页的数据,则 page_num=3, page_size=10。SQL就是:
SELECT * FROM students LIMIT 20, 10;
主要分为四大类:
- 算术运算符:
+,-,*,/,%(取模)。 - 比较运算符:
=,!=或<>,>,<,>=,<=,BETWEEN,IN,LIKE。 - 逻辑运算符:
AND,OR,NOT。 - 位运算符:
&,|,^(主要在底层使用,业务测试中较少涉及)。
+ (加), - (减), * (乘), / (除), % (取余/取模)。
会的,连表查询是工作中非常常用的技能,尤其是在需要从多个关联表中获取完整信息的时候。
用得非常多。当需要查询的信息分散在两张或多张表中,并且这些表之间可以通过某个公共字段(通常是主外键)进行关联时,就需要使用连表查询。
场景举例:我想查询一个学生的名字和他所在班级的名称。学生姓名在 students 表中,班级名称在 classes 表中,这两张表通过 class_id 字段关联。这时就必须用连表查询。
SELECT 字段列表 FROM 表1 INNER JOIN 表2 ON 表1.关联字段 = 表2.关联字段;
INNER 关键字可以省略。
例如:SELECT s.name, c.name FROM students s JOIN classes c ON s.class_id = c.id;
SELECT 字段列表 FROM 表1 RIGHT JOIN 表2 ON 表1.关联字段 = 表2.关联字段;
RIGHT OUTER JOIN 中的 OUTER 关键字可以省略。
主要就是内连接和外连接的语法,根据具体需求选择使用 INNER JOIN, LEFT JOIN 或 RIGHT JOIN。
这是一个很好的问题,考察的是对SQL操作的深度理解。
-
查:是标准操作,前面已经说明。
-
增 (INSERT):不能直接通过
JOIN向多张表中同时插入数据。必须分成多个INSERT语句,分别对每张表进行插入。 -
改 (UPDATE) 和 删 (DELETE):MySQL支持使用
JOIN语法来进行多表联合的更新和删除,但这属于高级用法,且语法相对复杂,在工作中为了逻辑清晰和安全,我们更常用的做法是**“先查后改/删”**。-
步骤:首先通过一个
SELECT ... JOIN ...语句,找出需要更新或删除的数据的主键ID。 -
然后,再用一个标准的
UPDATE或DELETE语句,配合WHERE id IN (...)子句,来对目标表进行操作。这种方式更安全、更易于理解和维护。例子
好的,这是电商业务中两个简单的两表联查增删改示例,使用 Markdown 格式。
1. 修改:给某个分类的所有商品打九折
这个操作通过关联
商品表和分类表,批量更新特定分类下所有商品的价格。- 场景: 运营人员希望对所有 “电子产品” 分类的商品进行促销,统一打九折。
- 涉及表:
products(商品表) 和categories(分类表)。
SQL 示例:
UPDATE products p JOIN categories c ON p.category_id = c.id SET p.price = p.price * 0.9 WHERE c.name = '电子产品';
操作解释:
UPDATE products p JOIN categories c ON p.category_id = c.id: 将products表和categories表通过category_id关联起来。SET p.price = p.price * 0.9: 将满足条件的商品价格更新为原价的90%。WHERE c.name = '电子产品': 指定条件,仅针对分类名称为 “电子产品” 的商品执行更新。
2.删除:删除所有已注销用户的购物车商品
这个操作通过关联
购物车表和用户表,删除所有已停用账户的购物车记录。- 场景: 为了清理无效数据,需要定期删除所有已注销(inactive)用户的购物车信息。
- 涉及表:
cart_items(购物车项目表) 和users(用户表)。
SQL 示例:
DELETE cart_items FROM cart_items JOIN users ON cart_items.user_id = users.id WHERE users.status = 'inactive';
操作解释:
DELETE cart_items FROM cart_items JOIN users ...: 指定从cart_items表中删除数据,并将它与users表关联。ON cart_items.user_id = users.id: 使用user_id作为两个表的连接条件。WHERE users.status = 'inactive': 筛选出users表中status字段为 "inactive" 的用户,然后删除cart_items表中所有与这些用户关联的记录。
-
子查询(Subquery),也叫嵌套查询,根据其返回结果和使用位置,可以分为几类:
- 标量子查询:返回结果是单个值(一行一列)。可以用在
WHERE,SELECT等子句中。 - 列子查询:返回结果是一列多行。通常用在
IN,ANY,ALL等操作符后面。 - 行子查询:返回结果是一行多列。
- 表子查询:返回结果是多行多列,相当于一个临时表。通常用在
FROM子句后面,必须给它起一个别名。
用得非常多。子查询可以让复杂的查询逻辑变得更清晰,分步解决问题。
场景举例:查询与“小明”在同一个部门的所有员工。
SELECT * FROM employees WHERE department_id = (SELECT department_id FROM employees WHERE name = '小明');
这里的 (SELECT ...) 就是一个标量子查询。
SELECT DISTINCT name FROM students WHERE gender = '男';
SELECT gender, COUNT(*) AS '人数' FROM employees GROUP BY gender;
SELECT * FROM employees WHERE gender = '男' ORDER BY salary DESC LIMIT 5;
SELECT COUNT(*) FROM products WHERE price BETWEEN 500 AND 1000;
SELECT * FROM students WHERE gender = '男' AND age BETWEEN 18 AND 22;
SELECT * FROM students WHERE gender = '男' ORDER BY age DESC LIMIT 1;
SELECT * FROM students WHERE gender = '女' AND age >= 18 ORDER BY age DESC;
SELECT class_id, AVG(age) AS '平均年龄' FROM students GROUP BY class_id;
SELECT * FROM students WHERE gender = '男' LIMIT 3, 5;
SELECT * FROM students WHERE age != 18;
或者
SELECT * FROM students WHERE age <> 18;
SELECT * FROM students ORDER BY class_id ASC, age DESC;
SELECT *
FROM employees
WHERE department_id = (SELECT department_id FROM employees WHERE name = '小明')
AND name != '小明';SELECT * FROM employees WHERE name LIKE '马%';
SELECT * FROM employees WHERE salary > (SELECT salary FROM employees WHERE name = '小明');
SELECT * FROM students WHERE age < (SELECT age FROM students WHERE name = '小明');
SELECT name, age FROM students WHERE gender = '男' AND age BETWEEN 20 AND 30 ORDER BY age DESC;
SELECT * FROM students s1
INNER JOIN students s2 ON s1.age = s2.age AND s1.id < s2.id;或者使用 GROUP BY 和 HAVING:
SELECT * FROM students
WHERE age IN (SELECT age FROM students GROUP BY age HAVING COUNT(*) > 1);SELECT * FROM products
WHERE price IN (SELECT price FROM products GROUP BY price HAVING COUNT(*) > 1);SELECT COUNT(*) FROM employees WHERE name LIKE '崔%';
假设有学生表 students 和成绩表 scores。
SELECT s.name
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id
WHERE sc.id IS NULL;或者使用子查询:
SELECT name FROM students WHERE id NOT IN (SELECT DISTINCT student_id FROM scores);
- 且 (AND):
SELECT * FROM users WHERE username LIKE '%小%' AND registration_time > '2023-01-01'; - 或 (OR):
SELECT * FROM users WHERE username LIKE '%小%' OR registration_time > '2023-01-01';
这个问题无法直接用SQL实现,因为它依赖于“第几个”这个顺序概念,而数据库中的行本质上是无序的,除非有一个明确的字段(如 birth_order 或 birth_date)来定义这个顺序。
如果假设有一个 birth_date 字段,可以这样查:
SELECT * FROM sons WHERE father_name = '张三' ORDER BY birth_date ASC LIMIT 1, 1;
SELECT score FROM scores WHERE student_name = '王小明';
如果分数和学生信息在不同表,需要连表:
SELECT sc.score FROM students s JOIN scores sc ON s.id = sc.student_id WHERE s.name = '王小明';
这6条内容,是从第5条开始,取6条。
SELECT * FROM students ORDER BY age ASC LIMIT 4, 6;
这是11条内容,从第20条开始,取11条。
SELECT * FROM table_name LIMIT 19, 11;
这是21条内容,从第50条开始。
LIMIT 49, 21
计算公式是: LIMIT [起始行号 - 1], [结束行号 - 起始行号 + 1]
这是一个高级问题。标准的 DISTINCT 或 GROUP BY 会改变结果的顺序。要保留原始顺序(比如按主键 id 的顺序),需要使用窗口函数 ROW_NUMBER()。
SELECT id, name, ...
FROM (
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY name ORDER BY id ASC) as row_num
FROM
users
) AS subquery
WHERE
row_num = 1;这个查询会根据 name 字段进行去重,并保留每个重复名字中 id 最小的那一条记录。
UPDATE 表名 SET 字段1 = 值1, 字段2 = 值2, ... WHERE 条件;
必须搭配 WHERE 子句。
如果省略 WHERE 子句,UPDATE 语句将会更新表中所有行的指定字段,这通常是一个灾难性的、不可逆的操作。
UPDATE employees SET phone = '新的手机号' WHERE id = 10;
UPDATE employees SET salary = salary + 2000 WHERE name = '小明';
UPDATE employees SET salary = 8000 WHERE age BETWEEN 20 AND 25;
UPDATE products SET price = price * 1.1;
UPDATE scores SET score = 98 WHERE student_id = 1 AND subject = '数学';
UPDATE students SET class_id = 3, age = 20 WHERE name = '小明';
DELETE FROM 表名 WHERE 条件;
DELETE FROM employees WHERE age < 18 AND gender = '男';
DELETE FROM students WHERE id IN (SELECT student_id FROM scores WHERE subject = '语文' AND score < 60);
这是一个经典的面试题,区别非常大:
| 特性 | DELETE | TRUNCATE | DROP |
|---|---|---|---|
| 语言类型 | DML (数据操作语言) | DDL (数据定义语言) | DDL (数据定义语言) |
| 操作对象 | 表中的行 (可指定) | 表中所有数据 | 整个表 (结构+数据) |
| WHERE子句 | 可以使用 | 不能使用 | 不能使用 |
| 事务 | 可以回滚 (Rollback) | 隐式提交,不能回滚 | 隐式提交,不能回滚 |
| 速度 | 逐行删除,速度慢 | 删除并重建表,速度快 | 直接删除表,速度最快 |
| 触发器 | 会触发 | 不会触发 | 不会触发 |
如果需要快速清空,且不需要回滚,推荐使用 TRUNCATE TABLE 表名;。
如果需要逐行删除,或者可能需要回滚,使用 DELETE FROM 表名;。
使用 ALTER TABLE 命令,主要操作有:
- 添加列:
ADD COLUMN - 删除列:
DROP COLUMN - 修改列:
MODIFY COLUMN(修改数据类型、约束),CHANGE COLUMN(修改列名+类型) - 添加约束:
ADD PRIMARY KEY,ADD FOREIGN KEY - 删除约束:
DROP PRIMARY KEY,DROP FOREIGN KEY - 修改表名:
RENAME TO
ALTER TABLE 旧表名 RENAME TO 新表名;
ALTER TABLE 表名 CHANGE COLUMN 旧字段名 新字段名 字段类型;
注意:CHANGE 后面需要带上字段类型,即使类型不变。
ALTER TABLE 表名 MODIFY COLUMN 字段名 新数据类型;
ALTER TABLE 表名 DROP COLUMN 字段名;
使用 INSERT INTO 语句。
INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);
INSERT INTO students (name, age, phone) VALUES ('小明', 18, '手机号码');
这个问题有歧义,学生信息和成绩通常不在一张表。假设都在 students 表:
INSERT INTO students (id, name, class_id, score) VALUES (100, '小红', 2, 95);
INSERT INTO employees (id, name, salary) VALUES (10, '小明', 10000);
CREATE TABLE 表名 (
字段1 数据类型 约束,
字段2 数据类型 约束,
...
PRIMARY KEY (主键字段)
);使用 CREATE TABLE 语句定义表结构即可。
有两种方式:
- 只复制表结构,不复制数据:
CREATE TABLE 新表名 LIKE 旧表名; - 同时复制表结构和数据:
CREATE TABLE 新表名 AS SELECT * FROM 旧表名;
就是复制一张表。CREATE TABLE 表名_backup AS SELECT * FROM 表名; 是最快的方式。
CREATE VIEW 视图名 AS SELECT 语句;
例如:
CREATE VIEW male_students AS SELECT * FROM students WHERE gender = '男';
ALTER TABLE 表名 ADD COLUMN 新字段名 数据类型 [约束];
例如,在 students 表后增加一个 email 字段:
ALTER TABLE students ADD COLUMN email VARCHAR(50);