Cheng Yu
3062 words
15 minutes
Software Testing

Cover image source: Source

  1. Linux常用命令
    • df: file system usage; du: current directory usage
    • grep(Global Regular Expression Print)全局正则表达式搜索, 它在一个或多个文件中搜索字符串模板。 如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到标准输出,不影响原文件内容。
    • kill -9 $(ps -ef | grep pro1): 先使用ps查找进程pro1,然后用kill杀掉 (其发送的信号为SIGKILL(9) ,将强制结束进程).
  2. 数据库联表查询
    • LEFT JOIN, RIGHT JOIN, INNER JOIN, CROSS JOIN…
  3. 索引失效的原因有哪些
    • 最左匹配原则:在使用复合索引(即包含多列的索引)进行查询时,数据库能够利用索引的条件是从索引的最左边开始并连续的。 如果一个复合索引包含(A, B, C)三列,那么只有当查询条件包含A列,或A和B列,或A、B和C列时,索引才会被有效利用。
  4. redis的数据结构有哪些
    • 字符串、列表、集合、哈希、位图(用于高效地存储和查询状态集合中各个元素的状态。它主要利用位来表示某个值的存在与否, 其中每个位(0或1)对应集合中的一个元素)。
  5. 测试相关:隐性和异常
  6. 怎么理解测试开发和开发
    • SWE也需要做测试的工作,SWE需要编写测试驱动的设计、单元测试、参与构建各种大小规模的测试等。
    • SWT也是一个开发者角色,只是工作重心在可测试性和通用测试基础框架上。 (SWT也要会写代码,代码要求并不比开发低,他们写代码的聚焦点是测试)
  7. 项目相关,选一个项目说难点
  8. Java的垃圾回收机制,反射机制
    • GC:
      • 标记-清除(Mark-Sweep):首先标记所有从根集合(如线程栈、静态字段等)可达的对象,然后清除所有未被标记的对象。
      • 复制(Copying):将内存分为两块,每次只使用一块。活动的对象被复制到未使用的那块内存中,然后清除正在使用的内存块。
      • 标记-整理(Mark-Compact):与标记-清除类似,但在清除未被标记的对象后,将存活的对象向一端移动,消除碎片。
      • 分代收集(Generational Collection):大部分JVM使用的是分代收集技术,将对象分为年轻代(Young Generation)、老年代(Old Generation) 和永久代(PermGen,Java 8之后改为元空间,Metaspace)。不同的对象根据存活时间的长短被分配到不同的区域,垃圾回收频率依据区域的特性而定。
    • Reflection:允许程序在运行时访问、检测和修改其自身的类和对象的属性,例如:类名,包名,所有属性的集合,所有方法的集合,构造方法的集合等。
      • 动态加载类:在运行时加载和使用类,如类加载器。
      • 检查类的结构:可以在运行时检查类的字段、方法和构造函数,有助于理解对象。
      • 动态调用方法:可以动态地调用任何对象的任何方法,即使在编译时未知。
      • 操作属性:可以在运行时读写对象的属性,包括私有字段。 虽然反射极为强大,但使用时应谨慎,因为它可能会破坏封装性,降低性能,并增加安全风险。在使用反射时,开发者需要确保代码的安全性和效率。
  9. java的多线程,线程的状态
    • java的多线程:Java中的多线程是通过Thread类和Runnable接口来实现的,它允许并发执行多个线程。
    • 线程的状态:新建(New)、可运行(Runnable)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)、终止(Terminated)
    • 线程同步:同步方法:通过在方法声明中添加synchronized关键字,使得方法在执行时持有对象的锁;同步块:可以更细粒度地控制同步,只在代码的特定部分加锁,通过synchronized块实现。 锁(Locks):ReentrantLock…
  10. java异常处理机制
    • 异常类层次(基于Throwable类的层次结构),其包括检查型异常(Checked Exceptions)和非检查型异常(Unchecked Exceptions)例如RuntimeExceptionError
    • try-catch-finally
    • 抛出异常:通过throw语句显式抛出
    • 异常链:在处理异常时,有时候可能需要将捕获的异常转换为另一种异常并抛出,同时保留原始异常的信息。这可以通过设置“cause”完成, 使用initCause方法或者通过传递一个异常到另一个异常的构造器来实现
  11. mysql的索引,b树索引和hash索引
    • 索引是优化查询性能、加速数据检索的重要工具。通过为数据库表中的一列或多列添加索引,可以快速定位到特定的数据行。
    • B-Tree Index:由于其有序性和支持多种类型的查询,B树索引非常适合大多数数据库场景,特别是需要频繁进行范围查询和排序的应用。
    • Hash Index:当查询主要是等值查询,且数据量不是特别大时(避免哈希冲突),可以考虑使用哈希索引,尤其是在内存中完全可以容纳的数据集上。
  12. redis的事务怎么执行
    • Redis的事务提供了一种执行多个命令的方式,这些命令在执行期间会按序进行,且不会被其他命令打断,确保命令序列要么全部执行,要么全部不执行。虽然Redis事务确保了命令的原子性, 但它不支持传统数据库中的回滚机制。如果事务中的某个命令执行失败,其余命令仍然会继续执行。
    • 开始事务、命令入队、执行事务、监控关键变量、取消事务
  13. 进程调度相关知识,常见的进程调度方式,先来先服务等
    • 先来先服务(FCFS)、短作业优先(SJF)、最短剩余时间优先(SRTF)、时间片轮转(Round Robin)
  14. 用非侵入式的测试方法和侵入式的方法有什么优缺点
    • 非侵入式:
      • 优点:不影响系统性能(非侵入式测试不涉及修改系统代码或结构,因此不会影响系统的运行状态或性能)、环境真实(可以在系统的真实操作环境中进行测试,这有助于捕获真实用户场景下可能出现的问题)、 适用于生产环境(由于不需要修改系统,非侵入式测试特别适合在生产环境中进行,例如监控系统性能和用户行为)
      • 缺点:测试覆盖有限(可能无法深入系统内部,因此对于某些内部错误和细节问题难以发现和诊断)、 依赖外部表现(测试结果高度依赖于系统的外部输出,有时可能无法准确地反映系统内部的状态)、自动化程度有限(非侵入式测试难以实现高度自动化,尤其是当涉及复杂用户交互时)
    • 侵入式:
      • 优点:深入测试(侵入式测试允许直接访问和修改系统内部的代码和数据结构,能够深入检查系统的内部行为和状态)、高度可控(测试人员可以精确控制测试的执行流程,能够模拟各种边界条件和异常情况)、 自动化和重复性(侵入式测试更易于自动化,可以重复执行相同的测试案例以验证问题的修复或进行回归测试)
      • 缺点:可能影响系统行为(修改系统的内部代码或结构可能会影响系统的正常功能和性能)、 高维护成本(随着系统的更新和变更,侵入式测试代码也需要相应的维护和更新)、实施复杂(需要深入了解系统的内部设计和实现,对测试人员的技能要求较高)
  15. python的装饰器
    • 装饰器本质上是一个函数,它接受一个函数作为参数并返回一个函数。当你把一个函数定义为装饰器并使用它来”装饰”另一个函数时,你实际上是在告诉Python,“请不要直接调用这个函数,而是先调用我的装饰器, 由装饰器来处理这个函数然后可能以某种方式调用它。
  16. 进程和线程的区别
    • 进程是一个运行中的程序的实例,它是系统资源分配和执行的独立单位,拥有自己的地址空间、内存、数据栈以及其他记录其运行轨迹的辅助数据。线程是进程中的一个执行流, 是CPU调度和执行的最小单位。一个进程可以包含一个或多个线程。
  17. http状态码5开头是什么、4开头是什么
    • 5xx:服务器错误类别(e.g. 500 Internal Server Error、502 Bad Gateway、504 Gateway Timeout)
    • 4xx:客户端错误类别(400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found)
  18. java中的序列化和反序列化
    • 序列化:指将对象的状态信息转换为可以存储或传输的形式的过程,通常用于将对象的状态保存到文件、数据库或在网络上进行传输。(持久化、深复制、网络通信)
    • 反序列化:将序列化的数据格式还原为对象的过程
    • 安全性:反序列化未知或未经验证的数据时可能存在安全风险。恶意的序列化数据可能导致漏洞或攻击;兼容性:在类定义更改后,序列化和反序列化可能会遇到兼容性问题。 为了维持版本兼容,可以使用 serialVersionUID 字段来控制版本;性能:序列化和反序列化过程可能比其他方式(如JSON或XML处理)更耗费资源。
  19. 全局变量和局部变量、静态变量的区别和适用场景
    • 全局变量:全局变量是在函数外部定义的变量,它们在程序的整个执行周期内都存在,并且在程序的任何部分都可以访问(除非被局部作用域覆盖)。
      • 适用场景:配置信息或常用数据需要在多个不同模块或函数间共享;单例模式的实现
    • 局部变量: 局部变量是在函数内部定义的变量,它们只在该函数的作用域内可见,当函数执行结束后,这些变量就会被销毁。
      • 适用场景:函数需要临时存储数据;当变量的值不需要在函数调用之间持久化时
    • 静态变量:静态变量可以是局部静态变量或全局静态变量。局部静态变量在函数内部定义,但它们不会在函数调用结束时被销毁。相反,它们的值在函数调用之间保持不变。 全局静态变量在全局作用域内定义,但它们的作用域限制在定义它们的文件内,对其他文件是不可见的。
      • 适用场景:局部静态变量允许函数保留状态,无需使用全局变量;全局静态变量可以避免在其他文件中的命名冲突
  20. 对比java和C++
    • Java为纯面向对象的语言,容易理解,编程更容易;
    • 跨平台,java是解释性语言,由于中间代码和平台无关因此,java语言可以跨平台执行,具有很好的移植性
    • Java提供了很多内置的类库,简化了开发人员的程序设计工作,多线程的支持,网络通信的支持,垃圾回收器
    • 去除了C++语言中难以理解、容易混淆的特性,例如头文件、指针、多重继承等,使得程序更加严谨、简洁
Software Testing
https://mason130.github.io/posts/st/test/
Author
Cheng(Mason) Yu
Published at
2024-04-10