TestNG TestNG是一个Java语言的测试框架,也是QA最常用的测试框架之一
TestNG官网文档地址:TestNG 文档 — TestNG Documentation
有时间再依据这个重新学下https://lwmzz.blog.csdn.net/article/details/129173343有代码实践 简介 TestNG 是一个测试框架,从单元测试(与其他类隔离的情况下测试一个类)到集成测试(测试由多个类、多个包甚至多个外部框架(如应用服务器)组成的整个系统)
编写测试通常是一个三步过程:
编写您测试的业务逻辑,并在您的代码中插入TestNG注解。 到 testng.xml 文件中或在build.xml中添加有关您的测试信息(例如,类名、您希望运行的组等) 运行TestNG 可以在欢迎页面找到一个快速示例
文档中主要概念:
套件由一个XML文件表示。可以包含一个或多个测试,并由<suite>标记定义 测试用例由<test>表示,可以包含一个或多个TestNG类 TestNG类是一个包含至少一个TestNG注解的Java类。它由<class>标记表示,可以包含一个或多个测试方法 测试方法是代码中的@Test注解的Java方法 可以通过@BeforeXXX和@AfterXXX注解进行配置,这些注解允许在某个特定点之前和之后执行一些 Java 逻辑,这些点可以是上述列表中的任何一项 其余部分将解释以下内容:
所有注解的列表以及简要说明。这将让您了解TestNG提供的各种功能,但可能需要查阅专用于每个注解的部分以了解详细信息。 testng.xml文件的说明,语法以及您可以在其中指定的内容。 各种功能的详细列表以及如何结合注解和testng.xml使用它们 注解 以下TestNG中可用注解及其属性的快速概述
注解:BeforeXXX & AfterXXX
TestNG类的配置信息:
@BeforeSuite:在此套件中的所有测试运行之前,将运行带注解的方法。 @AfterSuite:在此套件中的所有测试运行后,将运行带注解的方法。 @BeforeTest:在运行属于<test>标记内的类的任何测试方法之前,将运行带注解的方法。 @AfterTest:在运行属于<test>标记内的类的所有测试方法之后,将运行带注解的方法。 @BeforeGroups:此配置方法之前将运行的组列表。保证在调用属于任何这些组的第一个测试方法之前不久运行此方法。 @AfterGroups:此配置方法将在之后运行的组列表。保证在调用属于任何这些组的最后一个测试方法后不久运行此方法。 @BeforeClass:在调用当前类中的第一个测试方法之前,将运行带注解的方法。 @AfterClass:在运行当前类中的所有测试方法之后,将运行带注解的方法。 @BeforeMethod:带注解的方法将在每个测试方法之前运行。 @AfterMethod:带注解的方法将在每个测试方法之后运行 TestNG类的超类中的注解行为
超类是指被继承的类
超类中的注解行为会被继承到子类中。
执行顺序:
@Before 类注解 : 从超类到子类 @After 类注解:从子类到超类。 当放置在TestNG类的超类上时,上述注解也将被兑现(继承)。例如,这对于在公共超类中集中多个测试类的测试设置非常有用
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; public class BaseTest { @BeforeClass public void beforeClass() { System....
总体概述 docker是什么 是什么?
开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化 完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),且容器性能开销极低 基于 Go 语言开源的应用容器引擎,遵从 Apache2.0 协议开源 为什么?
一次构建,随处运行 更快速的应用交付和部署 更便捷的升级和扩缩容 更简单的系统运维; Docker与虚拟机对比
Docker的镜像层一般很小,只有几十KB,而虚拟机则通常以GB为单位。
性能方面,Docker依附于宿主机,所以性能接近宿主机,而虚拟机相对于原主机来说性能较差。资源利用率方面,Docker的资源利用率较高,而虚拟机的资源利用率较低。
隔离性方面,Docker和虚拟机都具有安全隔离的特性。
Docker直接在宿主机内核上运行,而虚拟机运行在隔离层Hypervisor上。
Docker可同时运行上千个容器,而虚拟机相对厚重,最多只能启动几十个。
在运行速度方面,Docker优于虚拟机,Docker容器的启动和停止可以在秒级实现,而传统的虚拟机方式要慢得多
架构
三个基础概念
镜像(image):Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器
镜像唯一标识是其 ID 和摘要,而一个镜像可以有多个标签 并非是像一个 ISO 那样的打包文件,是一个虚拟的概念。是由一组文件系统组成,或者说,由多层文件系统联合组成 容器(container): Docker 利用容器(Container)独立运行的一个或一组应用。容器是用镜像创建的运行实例。 可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
可把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写
仓库(repository):仓库(Repository)是集中存放镜像文件的场所
仓库注册服务器上存放着多个仓库,每个仓库中包含多个镜像,每个镜像有不同的标签(tag)
使用镜像 Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像
获取镜像
Docker 镜像仓库获取镜像的命令是 docker pull
$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] 对Docker Hub,如果不给出用户名,则默认为 library,就是官方镜像
$ docker pull ubuntu:18....
持久化 AOF 文件的内容是操作命令; RDB 文件的内容是二进制数据 AOF Redis 中 AOF 持久化功能默认是不开启的,需要我们修改 redis.conf
Redis 每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里
这保存写操作命令到日志的持久化方式,是 Redis 里的 AOF(Append Only File) 持久化功能,注意只会记录写操作命令,读操作命令是不会被记录的
Redis 是先执行写操作命令后,才将该命令记录到 AOF 日志里的
避免额外的检查开销 不会阻塞当前写操作命令的执行,因为当写操作命令执行成功后,才会将命令记录到 AOF 日志 风险:
执行写操作命令和记录日志是两个过程,那当 Redis 在还没来得及将命令写入到硬盘时,服务器发生宕机了,这个数据就会有丢失的风险 写操作命令执行成功后才记录到 AOF 日志,所以不会阻塞当前写操作命令的执行,但是可能会给「下一个」命令带来阻塞风险 执行过程:
Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区; 通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区 page cache,等待内核将数据写入硬盘; 具体内核缓冲区的数据什么时候写入到硬盘,由内核决定 写回硬盘策略: Always,「总是」,每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘; Everysec,「每秒」,每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,每隔一秒将缓冲区里的内容写回到硬盘; No,不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘 AOF重写机制
AOF 日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大 Redis 为了避免 AOF 文件越写越大,提供了 AOF 重写机制 机制是在重写时,读取当前数据库中的所有键值对,将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件 妙处在于:尽管某个键值对被多条写命令反复修改,最终也只需要根据这个「键值对」当前的最新状态,然后用一条命令去记录键值对 AOF后台重写...
数据类型及应用 https://onecompiler.com/redis可以进行实践
String String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值
数据结构实现主要是int和SDS
SDS 不仅可以保存文本数据,还可以保存二进制数据 因为 SDS 使用 len 属性的值判断字符串是否结束 SDS 获取字符串长度的时间复杂度是 O(1) SDS 结构里用 len 属性记录了字符串长度,所以复杂度为 O(1) Redis 的 SDS API 是安全的,拼接字符串不会造成缓冲区溢出 SDS 在拼接字符串之前会检查 SDS 空间是否满足要求,如果空间不够会自动扩容 常用指令
# 设置 key-value 类型的值 > SET name lin OK # 根据 key 获得对应的 value > GET name "lin" # 判断某个 key 是否存在 > EXISTS name (integer) 1 # 返回 key 所储存的字符串值的长度 > STRLEN name (integer) 3 # 删除某个 key 对应的值 > DEL name (integer) 1 批量设置 :...
事务 事务是由 MySQL 的引擎来实现,常见的 InnoDB 引擎它是支持事务的 并不是所有的引擎都能支持事务,比如 MySQL 原生的 MyISAM 引擎就不支持事务
特性 具体特性
原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节;事务在执行过程中发生错误,会被回滚到事务开始前的状态 一致性:事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态 隔离性:允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失 如何保证特性?
持久性是通过 redo log (重做日志)来保证的 原子性是通过 undo log(回滚日志) 来保证的 隔离性是通过 MVCC(多版本并发控制) 或锁机制来保证的 一致性则是通过持久性+原子性+隔离性来保证 隔离级别 MySQL服务端允许多个客户端连接,意味着 MySQL 会出现同时处理多个事务的情况 问题: 脏读:如果一个事务「读到」了另一个「未提交事务修改过的数据」 事务 A 是还没提交事务的,也就是它随时可能发生回滚操作,被读 不可重复读:一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况 事务A两次读取过程中,事务B进行修改且提交 幻读:一个事务内多次查询某个符合查询条件的「记录数量」,如果出现前后两次查询到的记录数量不一样的情况 事务A两次读取过程中,事务B进行修改且提交 隔离级别 读未提交:一个事务还没提交时,它做的变更就能被其他事务看到 读提交:一个事务提交之后,它做的变更才能被其他事务看到 可重复读:一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB 引擎的默认隔离级别 串行化:会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行 「可重复读」但是很大程度上避免幻读现象 针对快照读(普通 select 语句),通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的 针对当前读(select … for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那这个插入语句就会被阻塞,无法成功插入 四种隔级别实现 「读未提交」可以读到未提交事务修改的数据,所以直接读取最新的数据就好 「串行化」通过加读写锁的方式来避免并行访问; 「读提交」和「可重复读」通过 Read View 来实现的,它们的区别在于创建 Read View 的时机不同,大家可以把 Read View 理解成一个数据快照,就像相机拍照那样,定格某一时刻的风景。「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 Read View,而「可重复读」隔离级别是「启动事务时」生成一个 Read View,然后整个事务期间都在用这个 Read View 执行「开始事务」begin/start transaction 命令 执行了 begin/start transaction 命令后,并不代表事务启动了 只有在执行这个命令后,执行了第一条 select 语句,才是事务真正启动的时机 Read View在MVCC工作 Read View 有四个重要的字段: m_ids :在创建 Read View 时,当前数据库中「活跃事务」的事务 id 列表,注意是一个列表,“活跃事务”指的就是,启动了但还没提交的事务 min_trx_id :在创建 Read View 时,当前数据库中「活跃事务」中事务 id 最小的事务,也就是 m_ids 的最小值 max_trx_id :这个并不是 m_ids 的最大值,而是创建 Read View 时当前数据库中应该给下一个事务的 id 值,就是全局事务中最大的事务 id 值 + 1 creator_trx_id :创建该 Read View 的事务的事务 id InnoDB 存储引擎的数据库表,聚簇索引记录中包含下面两个隐藏列: trx_id:一个事务对某条聚簇索引记录进行改动时,会把该事务的事务 id 记录在 trx_id 隐藏列里 roll_pointer:每次对某条聚簇索引记录进行改动时,都会把旧版本的记录写入到 undo 日志中,这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录 通过「版本链」控制并发事务访问同一个记录时的行为叫 MVCC(多版本并发控制) 可重复读和读提交如何工作 可重复读隔离级别是启动事务时生成一个 Read View,然后整个事务期间都在用这个 Read View 读提交隔离级别是在每次读取数据时,都会生成一个新的 Read View 日志 undo log(回滚日志):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC...
MySQL查询过程 MySQL 的架构共分为两层:Server 层和存储引擎层
Server 层负责建立连接、分析和执行 SQL。主要包括连接器,查询缓存、解析器、预处理器、优化器、执行器等。另外,所有的内置函数(如日期、时间、数学和加密函数等)和所有跨存储引擎的功能(如存储过程、触发器、视图等。)都在 Server 层实现 存储引擎层负责数据的存储和提取。支持 InnoDB、MyISAM、Memory 等多个存储引擎,不同的存储引擎共用一个 Server 层。从 MySQL 5.5 版本开始, InnoDB 成为了 MySQL 的默认存储引擎。索引数据结构就是由存储引擎层实现,不同的存储引擎支持的索引类型也不相同,比如 InnoDB 支持索引类型是 B+树 ,且是默认使用,在数据表中创建的主键索引和二级索引默认使用的是 B+ 树索引 第一步:连接器 启动Mysql服务,连接 MySQL 服务
# -h 指定 MySQL 服务得 IP 地址,如果是连接本地的 MySQL服务,可以不用这个参数; # -u 指定用户名,管理员角色名为 root; # -p 指定密码,如果命令行中不填写密码(为了密码安全,建议不要在命令行写密码),就需要在交互对话里面输入密码 mysql -h$ip -u$user -p 查看 MySQL 服务被多少客户端连接
执行 show processlist 命令进行查看
MySQL 定义空闲连接的最大空闲时长,由 wait_timeout 参数控制的,如果空闲连接超过了这个时间,连接器就会自动将它断开
mysql> show variables like 'wait_timeout'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | wait_timeout | 28800 | +---------------+-------+ 1 row in set (0....
调度算法 进程调度 总论 当CPU空闲,操作系统就选择内存中的某个「就绪状态」的进程,并给其分配 CPU 什么时候会发生 CPU 调度 当进程从运行状态转到等待状态 当进程从运行状态转到就绪状态 当进程从等待状态转到就绪状态 当进程从运行状态转到终止状态 其中发生在 1 和 4 两种情况下的调度称为「非抢占式调度」, 2 和 3 两种情况下发生的调度称为「抢占式调度」 非抢占式:当进程正在运行时,会一直运行,直到该进程完成或发生某个事件而被阻塞时,才会把 CPU 让给其他进程 抢占式:进程正在运行的时,可以被打断,使其把 CPU 让给其他进程 先来先服务调度 先来后到,每次从就绪队列选择最先进入队列的进程,然后一直运行,直到进程退出或被阻塞,才会继续从队列中选择第一个进程接着运行 对长作业有利,适用 CPU 繁忙型作业的系统,而不适用 I/O 繁忙型作业的系统 最短作业优先调度 会优先选择运行时间最短的进程来运行,这有助于提高系统的吞吐量 显然对长作业不利,很容易造成一种极端现象 高响应比优先调度 每次进行进程调度时,先计算「响应比优先级」,然后把「响应比优先级」最高的进程投入运行 时间片轮转调度 每个进程被分配一个时间段,称为时间片,即允许该进程在该时间段中运行 最高优先级调度 对多用户计算机系统就有不同的看法,它们希望调度是有优先级的,即希望调度程序能从就绪队列中选择最高优先级的进程进行运行,这称为最高优先级调度 优先级可分为: 静态优先级:创建进程时候,就已经确定了优先级了,然后整个运行时间优先级都不会变化 动态优先级:根据进程的动态变化调整优先级,比如如果进程运行时间增加,则降低其优先级,就随着时间的推移增加等待进程的优先级 多级反馈队列调度 「时间片轮转算法」和「最高优先级算法」的综合和发展 「多级」有多个队列,每个队列优先级从高到低,同时优先级越高时间片越短。 「反馈」如果有新的进程加入优先级高的队列时,立刻停止当前正在运行的进程,转而去运行优先级高的队列; 内存页面置换 缺页异常(缺页中断)
当 CPU 访问的页面不在物理内存,便产生一个缺页中断,请求操作系统将所缺页调入到物理内存。与一般中断区别在于: 缺页中断在指令执行「期间」产生和处理中断信号,而一般中断在一条指令执行「完成」后检查和处理中断信号 缺页中断返回到该指令的开始重新执行「该指令」,而一般中断返回回到该指令的「下一个指令」执行 页面置换算法:当出现缺页异常,需调入新页面但内存已满,选择被置换的物理页面,也就选择一个物理页面换出到磁盘,然后把需要访问的页面换入到物理页 最佳页面置换
置换在「未来」最长时间不访问的页面,但无法实现 先进先出置换
选择在内存驻留时间很长的页面进行中置换,就是「先进先出置换」算法的思想 最近最久未使用置换
发生缺页时,选择最长时间没有被访问的页面进行置换,假设已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用 时钟页面置换
把所有的页面都保存在一个类似钟面的「环形链表」中,一个表针指向最老的页面
缺页中断时,首先检查表针指向的页面:
如果它的访问位位是 0 就淘汰该页面,并把新的页面插入这个位置,然后把表针前移一个位置; 如果访问位是 1 就清除访问位,并把表针前移一个位置,重复这个过程直到找到了一个访问位为 0 的页面为止 网络 I/O多路复用 服务用户数量...