一、服务端自动化测试工具
1、什么是自动化测试
自动化测试用例的编写必须遵守AIR(Automatable、Independent、Repeatable)原则,执行自动化用例应该像空气一样快速健壮,好的自动化测试需要具有自动化、独立性和可重复执行。 全自动化:输出结果需要人工检查的测试不是一个好的自动化测试,自动化测试中必须使用Assert来校验,不能使用system.out.print输出。 独立性:自动化测试不依赖于任何外界环境的影响。自动化测试属于持续回归范畴,每次有发布时自动化测试用例就会被自动执行。如果用例有对外部环境的依赖,很容易导致每次发布后自动化执行失败。 可重复性:自动化测试结果应该保持一致性,避免被测对象未改变的情况下,测试结果被改变。
2、自动化测试需要什么?
编写测试用例:结果的校验Assert;写测试组件、测试用例,测试用例可以由各个组件组合形成,可将第一个组件的输出作为第二个组件的输入形成一个完整的用例。\
自动化实验室:定时任务执行,可在jenkins上创建一个job,进行持续集成测试
发布卡点:发布后测试用例自动执行,执行失败不允许发布。
可以用java代码做接口测试:为什么要用代码做接口自动化测试呢?一些工具功能是有限制,很多公司需要一些特定的功能,工具不支持,只好用代码进行开发。一般用 Java 做自动化测试,主要利用 httpclient.jar 包,然后利用 JUnit 或者 TestNG 这样的单元测试工具,进行测试用例的开发,接着在 Jenkins 上创建一个 job,进行持续集成测试。
3、自动化测试工具需要具有哪些能力?
创建环境:接口运行时选择的环境,设置base_url来提高用例编写的效率
创建项目:项目里可有多个模块
创建模块:模块里可放置多个用例,即多个用例的组合
创建用例:可选择所在项目和模块,选择支持的类型GET/POST,GET类型的话可添加请求参数。POST可选择body类型,可选择JSON、data、params。可添加头部信息。
断言设置:提取变量功能,可从返回值中提取某个key,设置断言,判断返回值是否正确。
测试套件suit:将多个用例放在一个套间里,也可以用例和模块组合起来作为一个套件。
配置管理:可以将一些公共变量、参数、方法、请求头信息进行配置。方法为自定义的方法,平台提供一个编写的入口,编写后可以获取返回值,如方法引用格式为:`${function($para)}`。
设置hook:用例在执行前或后需要进行的操作,相当于`unittest`中的`setUp`和`tearDown`方法,testng中使用@BeforeClass注解实现用例执行前执行:函数是在众多函数或者说是在一个类类里面最先被调用的函数,而且每执行完一个函数都要从setUp()调用开始后再执行下一个函数,有几个函数就调用他几次,与位置无关,随便放在那里都是他先被调用。@AfterClass注解实现用例执行后执行:在众多函数执行完后他才被执行,意思就是不管这个类里面有多少函数,他总是最后一个被执行的,与位置无关,放在那里都行,最后不管测试函数是否执行成功都执行`tearDown()`方法;如果`setUp()`方法失败,则认为这个测试项目失败,不会执行测试函数也不执行`tearDown()`方法。
定时任务:测试套件还应该支持定时任务,方便回归测试,定时任务需要启动定时任务监听器。支持定时配置(支持crontab格式),接收邮件。
4、TestNg
4.1 什么是testng?
TestNg是JAVA中的一个单元测试框架,有完善的用例管理模块,配合maven很方便管理依赖第三方插件。使用JAVA注解去写测试用例,它包含Junit的所有功能,测试人员一般用TestNG来写自动化测试,开发人员一般用Junit写单元测试,TestNG适合测试人员使用的原因:比Junit涵盖功能更全面的测试框架;Junit更适合隔离性比较强的单元测试;TestNG更适合复杂的集成测试。
4.2 testng的优点是什么?
- 可生成测试报告:执行的测试用例数;通过的测试用例数;测试用例数量失败;跳过的测试用例数。
- TestNG简化了测试用例的编码方式。我们不必编写静态main方法。操作顺序仅由注释维护。
- TestNG框架可以轻松地与其他工具(例如Maven)集成。
- TestNG允许你单独执行测试用例。例如, 如果你有六个测试用例, 则为每个测试用例编写一个方法。当我们运行程序时, 成功执行了五个方法, 而第六个方法失败了。要消除该错误, 我们只需要运行第六种方法, 而这只能通过TestNG来实现。因为TestNG在测试输出文件夹中生成testng-failed.xml文件, 所以我们将仅运行该xml文件来执行失败的测试用例。
- TestNG框架中使用的注释很容易理解, 例如@ BeforeMethod, @ AfterMethod, @ BeforeTest, @ AfterTest。
- 通过将多个测试用例转换为一个testng.xml文件, 可以轻松地将它们分组, 在其中你可以设置每个测试用例的优先级, 从而确定应该首先执行哪个测试用例。
4.3 如何在testng中运行脚本
4.4 在TestNG中使用什么注释?
- 测试注解:@Test,在定义方法前边指定测试注解
- 前置条件注解:@BeforeClass类执行之前运行,@BeforeMethod方法执行之前运行,@BeforeSuite测试套件类在运行之前运行了Suite。
- 后置条件注解:@AfterClass类执行之后运行,@BeforeMethod方法执行之后运行,@BeforeSuite测试套件类在运行之后运行了Suite。
- 执行次数:@Test(invocationCount = 3) 设置重复运行的次数,相当于并发执行
public class TestAddTest {
@BeforeMethod
public void runBefore() {
System.out.println("方法之前运行");
}
@Test
public void testAdd() {
System.out.println(TestAdd.add(1,2));
}
@BeforeClass
public void runBefClass() {
System.out.println("在类之前运行");
}
@AfterClass
public void runAftClass() {
System.out.println("在类之后运行");
}
@BeforeSuite
public void runBefSuit() {
System.out.println("测试套件之前运行");
}
@AfterSuite
public void runAftSuit() {
System.out.println("测试套件之后运行");
}
@AfterMethod
public void runAfter() {
System.out.println("方法之后运行");
}
}
4.5 如何在TestNG中设置优先级?
如果不设置优先级,会按照首字母大小顺序执行,若需要按照所需的顺序执行,需要设置优先级。则使用@Test(priority = 3)
public class TestSuit1 {
// @Test(priority = 2)
@Test
public void test1() {
System.out.println("run2");
}
// @Test(priority = 1)
@Test
public void add() {
System.out.println("run1!");
}
// @Test(priority = 3)
@Test
public void cdt() {
System.out.println("run3");
}
}
public class TestSuit1 {
@Test(priority = 2)
public void test1() {
System.out.println("run2");
}
@Test(priority = 1)
public void add() {
System.out.println("run1!");
}
@Test(priority = 3)
public void cdt() {
System.out.println("run3");
}
}
4.6 什么是TestNG中的套件suit
如何一次运行多个测试类,为了解决这个问题,引入了TestSuit的测试套件的概念。不同测试类可以组装成一个具备测试相关功能的套件,这个套件叫TestSuit。比如具备购物基本流程的测试套件,有具备冒烟功能的测试套件等。 怎么写测试套件?可以在一个xml文件中将一次性运行的测试类写入进去,如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<test verbose="2" preserve-order="true" name="/Users/mac/code_learn/mytestng">
<classes>
<!--<class name="com.mytestng.AppTest">-->
<!--<!–<methods>–>-->
<!--<!–<include name="shouldAnswerWithTrue"/>–>-->
<!--<!–</methods>–>-->
<!--</class>-->
<class name="com.mytestng.TestSuit1"></class>
<class name="com.mytestng.TestAddTest">
</class>
</classes>
</test>
</suite>
4.7 什么是TestNG中的timeOut**
@Test( timeOut = 700)
上面的@Test批注告诉你将给测试方法700毫秒以完成其执行, 否则它将被标记为失败的测试用例。
4.8 如何通过testng.xml文件传递测试用例中的参数?
@Parameters({"par1","par2"})
@Test
public void test(String par1, String par2) {
System.out.println(par1 + "~~" + par2);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<test verbose="2" preserve-order="true" name="/Users/mac/code_learn/mytestng">
<parameter name="par1" value="aaa"></parameter>
<parameter name="par2" value="bbb"></parameter>
<classes>
<!--<class name="com.mytestng.AppTest">-->
<!--<!–<methods>–>-->
<!--<!–<include name="shouldAnswerWithTrue"/>–>-->
<!--<!–</methods>–>-->
<!--</class>-->
<class name="com.mytestng.TestSuit1"></class>
<class name="com.mytestng.TestAddTest">
</class>
</classes>
</test>
</suite>
4.9 在TestNG中@Listener注释的用途是什么?
TestNg中的Listener就是对一些接口提供的方法进行监听,我们可以重写这些方法达到我们想要监听测试用例的执行情况。
package com.mytestng;
import org.junit.Assert;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.annotations.Test;
/**
* @author tiantian.ytt
* @date 2021-10-22
*/
public class ListeneserDemo implements ITestListener {
@Override
public void onTestStart(ITestResult iTestResult) {
System.out.println("用例启动" + iTestResult.toString());
}
@Override
public void onTestSuccess(ITestResult iTestResult) {
System.out.println("执行成功" + iTestResult.toString());
}
@Override
public void onTestFailure(ITestResult iTestResult) {
System.out.println("执行失败" + iTestResult.toString());
}
@Override
public void onTestSkipped(ITestResult iTestResult) {
}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) {
}
@Override
public void onStart(ITestContext iTestContext) {
}
@Override
public void onFinish(ITestContext iTestContext) {
}
@Test
public void listeneDemoTest() {
Assert.assertTrue(11 == 10);
}
}
需要在testng.xml文件中分写入listeners进行监听。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<listeners>
<listener class-name="com.mytestng.ListeneserDemo"></listener>
</listeners>
<test verbose="2" preserve-order="true" name="/Users/mac/code_learn/mytestng">
<!--<parameter name="par1" value="aaa"></parameter>-->
<!--<parameter name="par2" value="bbb"></parameter>-->
<classes>
<!--<class name="com.mytestng.AppTest">-->
<!--<!–<methods>–>-->
<!--<!–<include name="shouldAnswerWithTrue"/>–>-->
<!--<!–</methods>–>-->
<!--</class>-->
<!--<class name="com.mytestng.TestSuit1"></class>-->
<!--<class name="com.mytestng.TestAddTest"></class>-->
<class name="com.mytestng.ListeneserDemo"></class>
</classes>
</test>
</suite>
4.10 如何禁用测试用例
我们可以使用enabled属性禁用测试用例的运行。我们可以将false值分配给enabled属性, 这样就可以禁用测试用例。
@Test(enabled=false)
4.11 断言
Assert为TestNG中的断言类:
1、Assert.assertTrue();
assertTrue()如果实际输出的结果是false,测试不通过,并停止执行。
2、Assert.assertFalse(); assertFalse()如果实际输出的结果是true,测试不通过,并停止执行。
3、Assert.assertEquals() assertEquals()如果值不等,就会停止执行,测试不通过。如果值相等就会继续执行。 assertEquals()方法包含很多不同参数类型的重载方法。
TestNG执行失败了,该失败的测试方法中后面的语句将会停止执行,但是其他的测试方法不受影响,可以继续执行。
4.12 控制部分执行
(1)利用groups参数
public class test{
@Test(groups = { "A", "B" })
public void testMethod1() {
System.err.println("groups = {A,B}");
}
@Test(groups = { "A" })
public void testMethod2() {
System.err.println("groups = {A}");
}
@Test(groups = { "B" })
public void testMethod3() {
System.err.println("groups = {B}");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
<groups>
<run>
<include name="A" />
<exclude name="B" />
</run>
</groups>
<test name="test" preserve-order="true">
<parameter name="url" value="http://123.57.56.45:7778/initLogin" />
<parameter name="username" value="999111" />
<parameter name="password" value="111111" />
<classes >
<class name="com.testng.test"/ >
</classes>
</test>
</suite>
执行结果:只会执行testMethod2
(2)利用methods中的include和exclude 如果在methods中标识了@test的方法,也可以在method中通过include和exclude来控制需要执行哪些方法
public class test{
@Test
public void testMethod1() {
System.out.println("testMethod1");
}
@Test
public void testMethod2() {
System.out.println("testMethod2");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
<test name="test" preserve-order="true">
<parameter name="url" value="http://123.57.56.45:7778/initLogin" />
<parameter name="username" value="999111" />
<parameter name="password" value="111111" />
<classes >
<class name="com.testng.test" >
<methods>
<include name="testMethod1" />
<exclude name="testMethod2" />
<include name="testMethod3" />
</methods>
</class>
</classes>
</test>
</suite>
先执行testMethod1,再执行testMethod3,这里也可以起到一个控制@test方法执行的作用,不需要在脚本中再添加priority 参数。
5、 Charles 工具
下载地址:www.charlesproxy.com/latest-rele…
主要用途:
- 用于移动端测试时抓包查看
- 设置网络代理,通过设置Map Remote功能,将网络请求重定向到另一个网络请求中,如线上网络接口代理到测试环境接口,用于测试环境的测试。
- 设置断点功能进行mock测试,可以对某个网络请求的request和response设置断点,当发起请求后会提示让更改请求体或返回值,在发起请求时前端已经计算响应时间,如果手动更高较慢,就会导致超时,达不到mock的效果,因此不建议使用设置breakpoints来mock测试。
- 设置Map Local将请求重定向到本地文件,当发起网络请求时,该请求的返回值走的时本地的json文件,达到mock测试的功能。
- rewrite功能:可重写接口的入参、返回值、返回值状态、cookie等达到mock测试的目的。
- 弱网测试:选择proxy中Throttle setting设置弱网,可填写弱网验证的接口,从上往下下拉列表选择对应强弱的网络,从上往下网络依次增强。
- 并发测试:选择并发测试的接口,右键选择Repeat Advanced,输入iterations(请求次数),concurrency(请求的并发数),delays(请求延迟),如果iterations为10,concurrency为2,则总共执行10个请求,2个同时执行。
- 限流测试:限流情况下,接口处理可能是返回409的状态码,可能是返回200且数据为空,当接口返回409情况下,mock进行测试,看前端页面展示是否符合产品预期,可通过rewrite功能重写response status为409。接口返回200返回值为空,可通过Map Local重定向到本地json文件,json文件为200返回值为空。
- 接口异常测试:姐口返回异常指接口返回的状态码并不是200,此时可以使用Charles 进行mock接口,将接口的返回状态码重写成非200,如409、404,在这种情况下,前端页面展示是否符合产品预期。通过rewrite功能重写response status非200。
6、Jmeter
是一款开源的性能测试工具,是一个轻量级的测试工具,jmeter是Java开发的,所以运行时候必须先要安装jdk才可以。jmeter是免安装的,拿到安装包后直接解压后使用即可。下载地址为:jmeter.apache.org/download_jm…
解压后直接sh jmeter.sh启动服务。除了做压力测试外还可以做接口测试。
1>、建立测试计划
添加线程组
2> 添加请求
也可先在添加请求之前增加逻辑控制器:吞吐量控制器,用于控制流量的比例。如设置吞吐量为80,即占总流量的80%。然后再将请求放在吞吐量控制器下。
3> 添加结果树 、添加聚合报告 、添加图形结果
4> 添加消息头
5> 上传文件,从文件中提取参数,作为接口的入参
6> 设置变量,当入参经常变化时,可设置成一个变量,方便管理。
在接口入参处可通过{XXX}获取文件中的数据,XXX为设置的csv数据文件设置的变量名称
7> 设置断言,在接口处设置响应式断言,如果要在线程组设置断言可放在线程组下。
对响应的文本、代码和响应头等设置断言
8> 设置断言结果
能将查看结果树中断言结果都输出到断言结果中,便于查看。
jmeter也可开发自己的sampler插件,如有些公司有自己的协议封装请求可能不是http的,如果想要使用jmeter调试该类接口,jmeter提供了jar包可自己开发jmeter插件。首先开发取样器的图形界面,扩展实现jmeter的AbstractSamplerGui类,然后开发取样器的处理逻辑类,扩展实现AbstractSampler类,实现协议交互,发送请求报文并处理返回的响应结果。最后将开发调试好的代码编译,于描述了依赖关系的pom.xml一起打成jar包,拷贝到Jmeter的lib/ext文件下,其他相关依赖的jar包拷贝到Jmeter的lib目录下。
7、自动化测试流量
8、JaCoCo代码覆盖率
测试覆盖率常被作为衡量测试好坏的指标,覆盖率分为两部分,即需求覆盖率和代码覆盖率。需求覆盖:测试人员对需求的了解来编写测试用例,用用例的执行结果来验证需求的实现,可以理解为黑盒覆盖。代码覆盖:为更加全面的覆盖还需要理解被测程序的逻辑,需要考虑每个函数的输入输出,逻辑分支代码的覆盖,这个时候我们的执行情况就以代码覆盖率来衡量,可以理解为白盒测试。在做单元测试时,常拿代码覆盖率作为测试好坏的指标。两者相辅相成,可以用代码覆盖的结果反向验证需求覆盖用例的测试是否完整。 1> 本地单元测试(idea+JaCoCo)
1.1 可使用idea自带的代码覆盖率工具
选择单元测试文件或文件夹,右键Run with Coverage
执行后会出现统计信息,这里需要注意单元测试的结构目录需要与被测代码的结果目录相同,否则可能出现统计的信息不准且不方便查看
1.2、 使用idea自带的代码覆盖率工具出的统计结果不太直观,并且没有将被测代码和未覆盖代码用不同颜色标注。因此可将jaCoCo插件集成到idea中生成测试报告,方便查看。
在pom文件中增加JaCoCo包和插件。
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
</dependency>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>0.60</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
刷新maven,会多出一个插件
执行测试用例,在插件中执行test或者执行命令mvn test
注意mvn test运行的是单测文件,需要在pom包中进行配置
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<!--<! -- testng.xml所在的路径,这里指的是相对路径 -- !>-->
<suiteXmlFile>src/suite/${suite.filepath}</suiteXmlFile>
</suiteXmlFiles>
</configuration>
<version>2.22.1</version>
</plugin>
运行成功后需要运行 JaCoCo report,生成覆盖率报告
用浏览器打开index.html,就能看到看到代码覆盖率报告,可点击进入具体的文件查看代码覆盖情况
红色背景:无覆盖,该行的所有指令均无执行。
黄色背景:部分覆盖,该行部分指令被执行。
绿色背景:全覆盖,该行所有指令被执行。
二、流量回放
2.1 什么是流量回放
记录线上的流量,在开发或者测试环境进行回放,通过对比录制和回放的差异来发现待测系统的问题。
2.2 流量回放的优势
流量回放要解决的问题:
(1)传统自动化测试遇到的问题
- 用例缺失,导致系统没有被完整回归,覆盖率难以保证;
- 造数据麻烦;
- 开发自动化测试脚本成本高;
- 运行效率低。 (2)日常需求迭代遇到的问题
- 基础组件升级不知道该怎么回归 中间件的升级、JDK升级、应用容器的升级等一系列升级,不知道对应用有什么影响,也不知道该怎么去测试;
- 测试覆盖率不全 测试造的数据远远没有线上真实用户的实际数据复杂,有的时候是根本想不到,有的时候,某些特定业务的数据,由于太复杂,根本造不出来
- 工作量大 对于日常迭代,测试将整体流程走完要几个小时的时间,重复且单调
- 需求、项目影响范围很难评估
代码发布前,影响范围很难评估,总怕某些点被遗漏了,线上出故障之后,受影响的功能和本次的发布毫无关系
2.3 流量回放的原理
三、UI自动化
四、性能巡检
一定时间内,对线上核心接口进行压测,对性能进行摸底,把低于基线QPS、资源损耗、响应时间的接口进行报警反馈。
五、性能测试
(1)【易】什么时候需要性能测试?
- 上线新模块/功能,且模块/功能对系统正常运行影响比较大时候,或者有重大功能上线时,怕对系统性能产生影响;
- 有线上促销活动需求,大促通常会导致系统流量翻增几十倍,压测能够提前知道系统是否能承受得住瞬间流量峰值,并为系统扩容提供依据;
- 线上服务需要扩容时;
- 性能调优后,需要评估调优的效果,进而决定是否还需要再次调优。 (2)性能测试的目的
- 获取正常请求流量下,系统的各个性能指标。指标包括:平均相应时间、响应时间分布情况、失败率等。CPU使用、内存、磁盘IO、网络IO等。
- 获取系统能够承受的极限容量、以及获取系统的性能瓶颈;
- 测试系统稳定性,系统稳定性要知道在各种情况下系统是否能稳定运行,造成系统不稳定的情况有:极限的每秒请求数、极限的并发数或连接数、突发流量高峰、长时间的压力流量、热点数据请求、差网络环境、下游模块慢返回、超时或故障假死等。
- 性能测试辅助系统参数调优:配合开发在不同系统参数或部署方案下,系统性能情况的对比;
- 系统性能回归。
(3)【中】性能测试的要点?难点?
要点: - 压测前要做好事前准备,如:影子表同步、限流开关确认、压测场景梳理、压测脚本准备、压测风险识别(设置合适的压测停止阀值即压测开关,提前准备针对压测流量的预案比如限流开关,要确认被压系统的流量监控是否到位,压测风险通知及是否涉及需要封网),周知被压系统上下游业务方。
- 压测中要注意数据的收集(CPU、QPS、RT、错误率等)、观察监控如有异常及时停止,周知上下游观察监控。
- 压测后要压测数据清理、限流开关、压测报告梳理。 难点
- 用户和业务模型分析搭建、对整个业务链路熟悉了解,构建压测模型;
- 压测脚本的开发;
- 压测瓶颈分析。 (4)【易】性能测试实施的步骤?
- 测试需求分析:被测系统中有负载压力需求的功能点有哪些,预计有多少用户并发访问。
- 测试方案制定
- 测试环境准备
- 测试脚本开发
- 测试场景执行:根据系统的不同业务需求来进行并发模拟测试,布置测试场景也是非常重要的,要想能真正测试出现场所出现的问题,必须要按实际的业务布置场景,来模拟用户的真实环境。
- 测试结果分析:在场景执行期间,Vuser会在执行事务的同时生成结果数据,要在测试执行期间监视场景性能,可以使用联机监视工具,也可以在测试执行后查看结果。需要看并发用户数、CPU、内存、响应时间、错误率。 (5)【易】性能测试评估的指标有哪些?
- 响应时间:从发起请求到收到请求响应的时间。
- 并发数:单位时间内发起请求的用户数。
- 吞吐量/吞吐率:衡量网络性能的重要指标。
- 资源利用率:CPU、内存、磁盘I/O(指单位时间内通过磁盘的数据量)、网络I/O(指单位时间内通过网络的数据量)。
- TPS/QPS。
(6)【难】CPU、内存、网卡资源未耗尽,但是 QPS 无法提升,可能原因是什么?
压测过程观察是不是数据库资源利用率过高。确认问题在哪里,是请求端到服务器,还是服务器到数据库,一般都是数据库瓶颈。
(7)【难】加压工具并发数、服务端连接数、线程数对性能测试的影响是什么 当数量超过服务器可以正常处理的范围。数量越多,越拥塞,性能越差。 (8)压测脚本的准备 使用jmeter调试压测脚本。 (9)当用户访问量大时,网络和数据库I/O就会成为瓶颈,需要想办法来降低接口耗时从而提高QPS。如何进行性能调优?\
- 空间换时间,内存、缓存就是典型的空间换时间的例子。利用内存缓存从磁盘上取出的数据,CPU请求数据直接从内存中获取,从而获取比从磁盘读取数据更高的效率。
- 时间换空间,当空间成为瓶颈时,切分数据分批次处理,用更少的空间完成任务处理。上传大附件时经常用这种方式。
- 分而治之,把任务切分,分开执行,也方便并行执行来提高效率。
- 异步处理,业务链路上有任务时间消耗较长,可以拆分业务,减少阻塞影响。常见的异步处理机制有MQ(消息队列),目前在互联网应用中大量使用。
- 并行,多个进程或者线程同时处理业务,缩短业务处理时间,比如我们在银行办理业务时,如果排队人数较多时,银行会加开柜台。
- 离用户更近一点,比如CDN技术,把用户请求的静态资源放在离用户更近的地方。
- 一切可扩展,业务模块化、服务化(同时无状态化)、良好的水平扩展能力。
六、测试流程
首先测试会参与需求评审,在需求评审中针对有问题的点跟开发产品探讨,不足地方要求产品修改。需求评审后,隔几天开发会对技术方案进行系分评审,测试人员站在测试的角度对整个系统设计上有问题点的可以提出质疑,提前发现质量问题。系分后对整个项目进行排期。之后便可对测试用例进行梳理编写,在开发联调前2天对测试用例进行评审。评审后便可将测试用例和开发自测用例录入到项目管理平台的用例中。开发提测前需要在用例平台中的自测用例跑通过后更改状态。 提测后第一天测试需要跑冒烟用例,用例不通过可对提测打回。冒烟通过后,正式进入测试,一般测试会有两轮测试,测试阶段留两天时间给产品和交互、设计进行验收。在测试阶段每天发测试日报,测试结束后对测试结果进行分析,编写测试报告,之后开发进行上线,上线过程中盯监控大盘,上线后对线上功能进行回归测试。
七、目前如何设计测试用例?什么样的测试用例才是好用例
好的测试用例,必须具备一下三个特征:
- 整体完备性:“好的”测试用例一定是一个完备的整体,是有效用例组合的集合,能够完成全覆盖测试需求。
- 等价类划分的准确性:指的是对于每个等价类都能保证只要其中一个输入测试通过,其他输入也一定测试通过。
- 等价类集合的完备性:需要保证所有可能的边界值和边界条件都已经正确识别。
三种最常用的测试用例设计方法 从理论层面上讲设计用例的方法很多:比如等价类划分,边界值分析法,错误推断法,因果图法,判定表驱动分析法,正交试验设计法,功能图分析法,场景设计法,形式化方法,扩展有限状态机方法等等,但是实际在企业的过程实践中,真正具有实用价值并且常用的只有前三种方法。 对于那些与生命相关的或者间接相关的软件,比如飞行控制,轨道交通的列车控制,医疗检测相关的软件或者系统,由于达到变态的测试覆盖率要求,会采用更多的设计方法。 能做到以上三点,就可以肯定测试是充分且完备的,即做到了完整的测试需求覆盖。
八、项目过程中,碰到的最大的困难是什么?怎么解决的?
(1)签到有时间限制一天签到一次,代码改造。Charles辅助。 签到有系统时间限制,只能一天签到一次,但是项目测试周期少于签到周期,并且需要短时间内回归完所有签到周期的case。这时候需要让开发修改代码,加debug,绕过当天时间的限制。当前端传改debug参数和签到时间时可将该天进行签到。模拟前端传参可通过Charles的rewrite功能来modify 入参。 (2)前端mock测试,前端接口有两个。一个解决跨域不返回数据(即预检的跨域请求:除get\post\head以外其他http方法,请求中出现自定义http头部,浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。这个过程对真实请求的调用者来说是透明的,参考文档www.w3cways.com/2280.html),… add header,其中增加的header为access-control-allow-credentials:true、access-control-allow-headers:Content-Type, X-Eleme-RequestID, X-ELEME-USERID, X-Shard, X-Captcha-Platform, X-Captcha-Session-Id, X-Captcha-Sig, X-Captcha-Token, X-NVC, X-UAB, X-UA, X-Alipay-Socrates、access-control-allow-methods:GET, POST, PUT, DELETE, PATCH, OPTIONS、access-control-allow-origin:要测试的H5页面地址。 (3)异常用例的构造,尽可能对项目需求、项目链路熟悉,梳理下游异常如超时、返回空等服务端如何处理,对这些异常的处理,前端应该怎么处理,跟产品核对异常情况下需求业务表现是什么,站在用户角度考虑是否合理。如下游异常是要走兜底逻辑(如查询是否在任务中,如果查询失败走兜底逻辑会触发再次发券,是否合理),还是不透出。
九、项目有哪些失败的实践,怎么总结教训?
二方包的改动没有识别到调用业务方,导致上线后发现线上bug, 这次失败,一定要确认好appId的owner,owner能识别到涉及的业务方,这样可以通知相应业务方回归测试,另外也暴漏出监控的缺失,如果监控完善,在上线灰度时就能发现问题。
十、项目有哪些做到不好的地方?有什么样的思考,来优化?
融合项目中(两个平台都能创建数据),需要将历史超级会员商家券活动数据推送到我们这边,调用我们的创建活动接口,由于数据量大,会有并发情况,需要测试并发,测试时发现创建了重复的数据,因为开发没有加redis锁。在上线时才发现,紧急修复。后续遇到可能并发的情况,需要进行并发测试。也要在测试前CR代码。
十一、怎么识别项目中的风险?怎么应对?
在需求评审阶段,对产品的需求逻辑就要仔细思考是否有逻辑风险,在项目前置阶段就规避风险。在开发系分阶段,对开发系统设计存在的漏洞,可能引起的线上问题都要跟开发讨论,规避掉风险。
十二、提了个bug,但开发认为不是bug,应该怎么办?
首先确认是否是测试环境不稳定或者是被测环境不是测试环境(比如没有切换环境,测到了线上环境)引起的,确认都不是,去查看日志,定位问题,定位是bug提交到bug管理系统,bug要有日志截图或者定位到代码错误处截代码。开发如果不改,需要让其在bug状态更改为wontfix,并说明原因。确实是重大问题需要测试reopen bug,如果开发还不改,需要跟开发说明影响范围,可能会造成资损等,如果还不改需要找到老大介入。如果是级别比较低的bug,跟开发或者设计协商,如果协商一致,将bug状态改为later,并备注原因。方便之后更改。
十三、怎么进行并发测试
可以借助jmeter进行并发测试,可设置线程数为并发执行的数量,点击运行按钮进行并发测试
也可借助Charles进行并发测试,选择并发测试的接口,右键选择Repeat Advanced,输入iterations(请求次数),concurrency(请求的并发数),delays(请求延迟),如果iterations为10,concurrency为2,则总共执行10个请求,2个同时执行。
十四、metaq的使用开发
十五、线上监控配置
十六、攻防演练
十七、什么是多活
十八、微服务架构
rpc:远程过程调用协议,是一个计算机通信协议,该协议允许运行在一台计算机的程序调用另一台计算机上的程序,RPC通过把网络通信抽象为远程的过程调用,调用远程的过程就像调用本地的程序一样方便,从而屏蔽了通讯复杂性,使开发人员无需关注网络编程细节。简单来说就是一台机器上调用另一台机器上的方法。
rpc的组成
- client: rpc协议的调用方
- service: 这个service并不是提供RPC服务器IP、端口监听的模块。是远程服务方法的具体实现,就是RPC接口的具体实现,其代码是最普通和业务相关的代码。
- Stub/Proxy: rpc代理,存在于客户端,即客户端的代理层,实现客户端对RPC的透明调用,不可能自行去管理消息格式、网络传输协议、也不可能自己去判断调用过程是否正常,这些工作就交给客户端的代理层去处理。
- Message Protocol: 一次完整的客户端服务端的交互肯定是携带某种两端都能识别的,共同约定的消息格式。RPC的消息管理层专门对网络传输所承载的消息进行编码和解码操作。
- Transfer/Network Protocol: 传输协议层,管理RPC框架所使用的网络协议、网络IO模型。传输层还需要统一客户端服务端所使用的IO模型。
- Selector/Processor:是一种负责执行RPC接口实现的角色,包括:管理RPC接口的注册、判断客户端的请求权限、控制接口类实现类的执行等。
- IDL: 接口定义语言。并不是RPC实现中所必须的,但是有跨语言的RPC框架就一定有IDL的存在。比如客户端是PHP,服务端是JAVA语言。
thrift: 协议就只是一套规范,那么就需要有人遵守规范来进行实现,那么thrift就是实现rpc的应用工具。Thrift是Facebook开发的跨语言的RPC服务框架。随后贡献给Apache开源组织。成为RPC服务的主流框架。优点: 跨语言,支持java、c/c++、python等多种编程语言、IDL定义接口函数和数据类型、支持二进制传输,效率高、支持多种工作模型,单线程模型、线程池模型、非阻塞模型。缺点:文档不多、各版本不兼容,升级不方便。 JAVA 实现的thrift例子:www.jianshu.com/p/52fa63b22…