# Java-autoTest **Repository Path**: jianghao233/Java-autoTest ## Basic Information - **Project Name**: Java-autoTest - **Description**: 学习自慕课网《Java接口自动化测试》,记录学习笔记与代码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2018-09-11 - **Last Updated**: 2022-11-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Java-autoTest ## 基于 Java 的接口自动化测试 ##[我的博客](https://blog.csdn.net/jianghao233/article/details/82423666) ## 一、接口自动化测试 ## 1.接口定义 接口:对外暴露的一个统一规范的接入点。 ## 2.为什么要做接口测试 1.更容易实现持续集成(背景就是第三点)      如何理解持续集成:      说背景---大型系统更多更复杂,系统间模块越来越多,组装的过程中出现的问题也越来越多,需要不断的迭代,不断的解决问题             2.自动化测试落地性性价比更高、比UI更稳定 3.大型系统更多更复杂,系统间模块越来越多 4.BUG 更容易定位,分模块进行测试 5.降低开发成本、提高效率(bug 发现越早,修复成本越低) ## 3.接口自动化测试开发技能树     1.开发语言:(如 Java) 2.开发框架(如 TestNG、HttpClient)  3.Mock 技术(好处:1.在开发完成之前,要先模拟出接口调试测试代码  2.集成:前后端分离,将接口提供给前端开发人员使用,有测试产出)     4.数据持久层框架(如 MyBatis)     5.持续集成工具 (如 JenKins)     6.接口协议相关知识 (如 HTTP 协议) ## 4.接口自动化测试落地过程 产品开发阶段: 1.需求阶段(测试人员了解客户需求、解决用户痛点)    2.研发阶段 (测试人员的价值开始体现,如利用Mock 技术将接口提供给前端,提高整体的开发效率) 3.测试阶段 (测试人员的主要负责阶段) 4.项目上线 ## 二、接口测试的用例设计 ## 1.接口测试范围 1.功能测试:验证产品逻辑是否正确 2.异常测试 null : 是开发过程中特定指的一个对象为空的端符,就是一个空对象,不指向任何内存地址 " " : 指一个空字符串,代表该对象有值,指向一个空地址 负载均衡架构:测试某一个后台(Tomcat 4)挂了,挂了之后 Tomcat4的请求会直接返回一个错误(前台1个nginx ,后台多个 Tomcat),测试是否会返回这个错误,能否会使用户访问失败;一段时间后,想让 Tomcat4 重新加入,判断能否重新加入集群中并正确处理所有请求。 冷热备份:冷备份不常见,热备份:前面有4个Tomca,后面有4个Tomca备份,如果Tomca4挂了,判断Tomca4的备份能否顶替之前的,仍然保持4个服务器存活;当Tomca4 正常后,判断能够成为Tomca4的备份。 3.性能测试 ##2.自动化接口测试范围 功能测试  +  数据异常测试 环境异常测试示例: ## 三、手工接口测试到自动化框架设计 ## 手工接口测试的常用工具 1.Postman 2.HttpRequest 3.Fiddler(具备抓包和发送请求功能) 半自动化:Jmeter(结果统计方面不完善) ###自动化框架的设计 ## 四、测试框架TestNG ## 1.TestNG 适合测试人员使用的原因: 1.比 Junit 涵盖功能更全面的测试框架 2.Junit 更适合隔离性比较强的单元测试 3.TestNG 更适合复杂的集成测试(特别适合接口测试) ## 2.TestNG 的使用 ## 3.TestNG 基本注解与执行顺序实战 ### 1. 方法 ### @Test : 最基本的注解,用来把方法标记为测试的一部分 ### @BeforeMethod : 在测试方法之前运行的标签 ### @AfterMethod : 在测试方法之后运行的标签 ### 输出效果: ### 2. 类 ### 使用场景:在类正式运行之前,是否需要注册对象或一些静态的方法或变量赋值在该方法里写,写完之后其他的方法中可以使用; ### @BeforeClass : 在类运行之前运行的方法 ### @AfterClass : 在类运行之后运行的方法 ### 输出效果: ### 3. 测试套件 Suite 执行顺序在 类 的顺序之前 ,Suite 可以包含多个 class ,这个类属于某个测试套件之下,在运行之前可以包含多个 class, 执行顺序 是 Suite --- class --- Method ### @BeforeSuite : BeforeSuite测试套件 ### @AfterSuite : AfterSuite测试套件 ### 输出效果: ### 4. 套件测试实例 ### 1.新建 LginTest.java :写测试主要的 Test 下包含的方法,登录测试--淘宝登录成功。 ### 2.新建 SuiteConfig.java :写测试套件之前运行的方法(共有的) ### 3.新建 PayTest.java : 支付测试--支付宝支付成功 ### 3.新建 Suite.xml :放置测试套件的配置文件--Suite 取名 test(必须有 name 属性),用 test 包裹不同的组件,每个 test 包含 SuiteConfig 与 Test。 ### 输出效果: ### 输出顺序: 测试套件包裹的在最外层,suite 先运行,输出 before suite;再运行测试标签 test ,即运行 beforeTest;接着运行第一个测试标签 test 里的 class(Login),输出 淘宝登录成功; 第一个测试标签 test 结束,即运行 aterTest,接着同理运行第二个测试标签 test 里的 class(pay),输出 支付宝支付成功;test 结束,即运行 aterTest;整个测试套件结束,输出 after suite。 ### 5. 忽略测试 ### 定义:本次测试执行并不想执行这个测试,将其忽略即可 ### 新建 IgnoreTest.java : 想忽略测试方法,在 @Test 方法后添加 (enabled = false) 即可;若添加 (enabled = true) 则也会执行,不会忽略。 ### 输出效果: ### 6. 组测试中的方法分组测试 ### 定义:把很多测试方法归到一个组里面,再进行方法的渲染。 ### 新建 groups 包 ,创建 GroupsOnMethod.java :在 @Test 方法后添加 (groups = 名称) 即可,建立 4个 Test ,2个 groups 为 server,2个 groups 为 client;建立 @BeforeGroups("server")、@AfterGroups("server")、@BeforeGroups("client")、 @AfterGroups("client") 输出 ### 输出效果: ### 7. 组测试中的类分组测试 ### 创建 GroupsOnClass1.java : 设置 @Test(groups = "stu"),建立 stu1 / stu2 对象,是 GroupsOnClass1 ### 创建 GroupsOnClass2.java :设置 @Test(groups = "stu"),建立 stu1 / stu2 对象,是 GroupsOnClass2 ### 创建 GroupsOnClass3.java :设置 @Test(groups = "teacher"),建立 teacher1() / teacher2() 对象,是 GroupsOnClass3 ### 创建 groupsOnClass.xml : 类测试的配置文件,设置2组test,会执行两次; ### 输出效果: ### groupsOnClass.xml : 设置 ` ` ,只执行 stu 对象; ### 输出效果: ### 8. 异常测试 ### 什么时候会用到异常测试? (在我们期望结果为某一个异常的时候) 比如:我们传入了某些不合法的参数,程序抛出了异常,也就是说我的预期结果就是这个异常。 ### 创建 ExpectedException.java :创建一个测试结果会失败的异常测试 runTimeExceptionFailed(),设置 @Test(expectedExceptions = RuntimeException.class); ### 输出效果: ### 在ExpectedException.java :创建一个成功的异常测试 runTimeExceptionSuccess(),设置 @Test(expectedExceptions = RuntimeException.class) ### 输出效果: ### 9. 依赖测试 ### 定义:本个测试方法执行的时候依赖其他的方法。 ### 创建 DependTest.java :创建 test1() 和 test2()方法,test2()依赖于test1(),给test2设置 @Test(dependsOnMethods = {"test1"});当test1()执行完成后再执行test2();若test1()执行失败则test2()不再执行; ### 当 test1 执行成功 ;输出效果: ### 当 test2 执行失败 ;输出效果: ### 10. 参数化测试 ### 定义:如何通外部或内部传递参数。 ### 创建包 com.course.testng.paramter : 创建 ParamterTest.java : @Parameters({"name","age"}) --传递参数(两个变量) ### 创建配置文件 Paramter.xml :放置配置文件,数据来源于该文件中类 ParamterTest ### 输出效果: ###将参数直接传到方法里 ### 在包 com.course.testng.paramter : 创建 DataProviderTest.java :创建 @Test(dataProvider = "data") 和 @DataProvider(name="data"),数据放在 providerData() 中; ### 输出效果: ### 通过方法名传递参数 ### 在 DataProviderTest.java :创建 @Test(dataProvider = "methodData") 和 @DataProvider(name="methodData") ### 执行 test1:输出效果: ### 执行 test2:输出效果: ### 执行 test:输出效果: ### 11. 多线程测试 ### 通过注解实现多线程测试 ### 创建包 com.course.testng.multiThread : 创建 MultiThreadOnAnnotion.java : @Test(invocationCount = 10,threadPoolSize = 3) --用10个线程来执行,设置现场池为3 ### 输出效果: ### 通过配置文件xml实现多线程测试 ### 在包 com.course.testng.multiThread : 创建 MultiThreadOnXml.java : @Test(invocationCount = 10,threadPoolSize = ###创建配置文件 multiThread.xml :放置配置文件,设置`` --设置多线程是方法级别,线程数是2 1.tests级别:不同的test tag下的用例可以在不同的线程下执行,相同的test tag下的用例只能在同一个线程中去执行 2. classs级别:相同的class tag 下的用例在同一个线程中执行, 不同的class tag 下的用例可以在不同的线程中执行 3. methods级别:所有用例都可以在不同的线程下去执行 4.thread-count:代表了最大并发线程数 5.xml文件配置这种方式不能指定线程池,只有方法上才可以指定线程池 ### 12. 超时测试 ###定义:测试多长时间没有响应 ### 在包 com.course.testng : 创建 TimeOutTest.java :设置属性 @Test(timeOut = 3000)--单位为毫秒值 ,期待在3秒内得到响应结果 ### 测试成功输出效果:(超时3秒,线程睡眠2秒) ### 测试失败输出效果:(超时2秒,线程睡眠3秒) ## 五、测试报告 ## TestNG 测试报告展示 ## ReportNg 测试报告 ## 一 、ExtentReport 介绍 [ExtentReport 官网](http://extentreports.com/) ## 1.新建 Maven project Chapter6 ## 配置 ExtentReport : 在 Pom.xml 中,通过 `` 将 extentreports 导入 ## 新建 包 com.tester.extend.demo ,新建 TestMethodsDemo.java : 添加 TestNG 断言、日志及抛出异常 `Reporter.log("这是我们自己写的日志");` `throw new RuntimeException("这是我自己的运行时异常");` ## 新建配置文件 testng.xml :配置测试模块与监听器 ,测试报告加载失败(.css 加载不出来,因为被“墙"了) ### 加载失败输出效果: ### 解决上述问题:新建 TestMethodsDemo.java : ExtentTestNGIReporterListenerOld.java ,放置从网上看到的解决方案代码;在 ExtentTestNGIReporterListener .java 中:怎么样解决cdn.rawgit.com访问不了的情况 -- 添加代码 `htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);` ### 解决样式加载不出的输出效果: ## 六、Mock接口框架的应用实战(模拟接口) ## 1.功能介绍 : 1.开发人员的接口功能 :get 方法、post 方法、header、cookie等 2.可以给前端人员使用的接口(后端人员没有写好前端要用的接口) 3.技术点 : 使用 Moco 框架(可以模拟网络协议) [下载地址](https://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/0.11.0/) 下载 moco-runner-0.11.0-standalone.jar 包 ; ## 新建 Chapter7 ,在其中新建 startup1.json 测试文件 --设置测试端口8899 ### 加载成功输出效果: ## 2. Moco框架的http协议带参数的get方法Mock实现 : ## 在 Chapter7 中,在其中新建 startupGet.json :queries 存放参数 ### 加载成功输出效果: ## 3.Moco框架的http协议post方法Mock实现 : ## 在 Chapter7 中,在其中新建 startupPost.json : ### 加载成功输出效果: ## 4.Moco框架的http协议带参数的post方法Mock实现 : ## 在 Chapter7 中 startupPost.json :"forms" 存放参数 ### 加载成功输出效果: ## 5.带cookies信息的get请求 ## 在 Chapter7 中,在其中新建 startupWithCookies.json :在 cookies 中存放 cookie 信息 ### 加载成功输出效果: ## 6.带cookies信息的post请求 ## 在 Chapter7 中,在 startupWithCookies.json :在 json 中存放参数信息,在 response 中 添加状态码 status ; ### 加载成功输出效果: ## 7.带有headers信息的mock请求 post 和 get 方法中添加 headers信息 方法相同,因为都是 Request 中的内容; ## 在 Chapter7 中,在其中新建 startupWithHeader.json :在 headers 中存放headers 信息(对数据格式的要求) 使用 json 存放参数信息(不能使用queries) ### 加载成功输出效果: ## 8. 实现请求重定向 ## 在 Chapter7 中,在其中新建 startupWithRedirect.json :redirectTo 重定向的网址 ### 加载成功输出效果:(重定向之前) (重定向之后) ## 七、Http 协议接口 ## 1. 在浏览器中查看http协议信息头 ### 展示输出效果 ## 2. 请求头信息字段含义介绍 ### HTTP 协议信息头 -- 常用请求头信息 1.Accept : 表示浏览器告诉服务器它所支持的数据类型 2.Accept-Charset : 表示浏览器告诉服务器它采用的字符编码格式(utf-8) 3.Accept-Encoding : 表示浏览器告诉服务器它所支持的压缩格式(gzip) 3.Accept-Language : 表示浏览器告诉服务器它采用的语言(zh-CN) 4.Host :表示浏览器告诉服务器它想访问哪台主机 5.If-Modified-Since :表示浏览器告诉服务器它缓存数据时间是多少 6.Referer :表示浏览器告诉服务器是从那个网页点过来的(防盗链:必须从指定的页面跳转过来) 7.User-Agent:表示浏览器告诉服务器它所使用的浏览器类型、版本等信息 8.Date:表示浏览器告诉服务器它何时访问的 9.X-Requested-With:XMLHttpRequest --表示浏览器告诉服务器它的请求方式(同步/异步)【前端使用 Ajax 技术】 ### HTTP 协议信息头 -- 常用响应头信息 1.Location : 表示服务器告诉浏览器去找那个服务器,配合302状态码使用【转发】 2.Serve:表示服务器告诉浏览器它的类型 3.Content-Encoding :表示服务器告诉浏览器回送的数据采用的压缩格式 4.Content-Type :表示服务器告诉浏览器回送的数据类型 5.Last-Modified:表示服务器告诉浏览器数据的最后修改时间 6.Refresh:这个头用于控制浏览器定时刷新 7.Content-Disposition :表示服务器告诉浏览器需要以下载方式打开回送的数据 8.Transfer-Encoding :表示服务器告诉浏览器数据是以分块形式回送的 ## 3. cookie与session的区别点 cookie 在客户端的头信息中;session 在服务存储、文件、数据库等可以;一般来说session的验证需要cookie带一个字段来表示这个用户是哪一个session,所有当客户端禁用cookie时,session将失效 ### cookie 的总结 1.cookie 就是一小段文本信息 2.cookie 的格式为 key:value ; key : value 3.cookie的值由服务端生成,客户端保存 ## 八、测试框架HttpClient ## 1. HttpClient简介及第一个demo [HttpClient](http://hc.apache.org/) :模拟Http客户端的一种技术,可以实现 get \ post 两种实现方式 ## 新建 Chapter9 ,在其中的配置文件 pom.xml 中引入 httpclient ;新建包 com.course.httpclient.demo ,在其中新建 MyHttpClient.java :完成 get 方法的展示(重定向到百度) ### 展示输出效果 ## 2. Mock一个返回Cookies信息的请求 ### 在 Chapter7 中的 startupWithCookies.json 中添加相关配置信息 : ### 展示输出效果 ## 3. 配置优化方法 ## 在 Chapter9 ,新建包 com.course.httpclient.cookies ,在其中新建MyCookiesForGet.java: 要将访问路径写在配置文件中,新建配置文件application.properties,设置`test.url=http://localhost:8899` ,`getCookies.uri=/getCookies`; 通过配置文件管理访问路径十分方便; 在MyCookiesForGet.java: `bundle = ResourceBundle.getBundle("application", Locale.CHINA);` 通过此句来配置加载方式(从 application 读取)。抽离配置文件,将访问路径写活; ### 展示输出效果 ## 4. 获取Cookies信息 在MyCookiesForGet.java:设置 `CookieStore.store = client.getCookieStore();` 获取cookies信息 ### 展示输出效果 ## 5. 携带Cookies信息访问get请求 在进行测试工作时,获取 cookie 的是接口,访问另一个接口需要带着cookie;故有两个cookie访问。 在MyCookiesForGet.java: 新建 testGetWithCookies() ,并设置依赖 `@Test(dependsOnMethods = {"testGetCookies"})` ; 带人 cookie 信息:`client.setCookieStore(this.store);` ; 接收 cookie 信息:`HttpResponse response = client.execute(get);` 获取响应的状态码:`int statusCode = response.getStatusLine().getStatusCode();` ### 展示输出效果 ## 6. HttpClient Post方法的访问实战 ## 在 Chapter9 的包 com.course.httpclient.cookies ,在其中新建MyCookiesForPost.java:新建 testPostMethod() ,并设置依赖 `@Test(dependsOnMethods = {"testGetCookies"})` ; ### 步骤: 1.声明一个Client对象,用来进行方法的执行:`DefaultHttpClient client = new DefaultHttpClient();` 2.声明一个方法,这个方法就是post方法:`HttpPost post = new HttpPost(testUrl);` 3.添加参数:` param.put("name","huhansan");` `param.put("age","18");` 4.设置请求头信息 设置header:`post.setHeader("content-type","application/json");` 5.将参数信息添加到方法中:`StringEntity entity = new StringEntity(param.toString(),"utf-8");` 6.声明一个对象来进行响应结果的存储:`String result;` 7.设置cookies信息:`client.setCookieStore(this.store);` 8.执行post方法:` HttpResponse response = client.execute(post);` 9.获取响应结果:`result = EntityUtils.toString(response.getEntity(),"utf-8");` 10.处理结果,就是判断返回结果是否符合预期;将返回的响应结果字符串转化成为json对象:`JSONObject resultJson = new JSONObject(result);` 11.获取到结果值:`String success = (String) resultJson.get("huhansan");` ` String status = (String) resultJson.get("status");` 12.具体的判断返回结果的值:`Assert.assertEquals("success",success);` `Assert.assertEquals("1",status);` ### 展示输出效果 ## 九、实战接口开发SpringBoot ## 1. springboot简介及官方demo开发 [spring boot官网](http://spring.io/projects/spring-boot) ## 新建 Chapter10 ,在其中的配置文件 pom.xml 中将 `org.springframework.boot`的包引用移动到项目目录下的主配置文件 pom.xml 中 ,避免Chapter10中存在多个父集;新建包 hello ,在其中新建 SampleController.java :完成 demo 搭建(复制官网示例代码快速搭建项目) ### 展示输出效果 ## 2. 返回cookies信息的get接口开发 ### 在Chapter10 中新建 Application.java:(默认入口类);新建包 com.course.server,新建MyGetMethod.java;新建 application.properties 配置端口号; MyGetMethod.java中: @RequestMapping(value = "/getCookies",method = RequestMethod.GET) public String getCookies(HttpServletResponse response){ Cookie cookie = new Cookie("login","true"); response.addCookie(cookie); return "恭喜你获得cookies信息成功"; } ### 展示输出效果 ## 3. 携带cookies信息访问的get接口开发 ### 在Chapter10 中 MyGetMethod.java 中;新建类getWithCookies ,设置 ` @RequestMapping(value = "/get/with/cookies",method = RequestMethod.GET)` 判断数组是否为空:` if(Objects.isNull(cookies))` ### 接口成功输出效果 ### 必须携带cookies信息才成功输出效果 ## 4. 需求携带参数的get请求两种开发方式 ### 开发一个需要携带参数才能访问的get请求。第一种实现方式 url: key=value&key=value,模拟获取商品列表案例 新建 ` public Map getList(@RequestParam Integer start,@RequestParam Integer end)`,设置 `@RequestMapping(value = "/get/with/param",method = RequestMethod.GET)` ### 成功输出效果 ### 开发一个需要携带参数才能访问的get请求。 第二种需要携带参数访问的get请求,模拟获取商品列表案例 新建 ` public Map myGetList(@PathVariable Integer start,@PathVariable Integer end)`,设置 `@RequestMapping(value = "/get/with/param/{start}/{end}")` ## 5. SpringBoot集成SwaggerUI ### SwaggerUI:自动生成接口文档的类似于插件的东西,使用它后可以不用再写开发文档了; ### 在Chapter10 中的 pom.xml 中,导入 `springfox-swagger2` 和 `springfox-swagger-ui` ; 新建包 com.course.config ,在其中新建 SwaggerConfig.java 存储Swagger 配置文件,使用 @Bean 注解的方式; 在MyGetMethod.java 中,添加注解 `@Api(value = "/",description = "这是我全部的get方法")` ,以及各方法的 @ApiOperation 描述,例如 `@ApiOperation(value = "要求客户端携带cookies访问",httpMethod = "GET")` ;`@ApiOperation(value = "需求携带参数才能访问的get请求方法一",httpMethod = "GET")`;`@ApiOperation(value = "需求携带参数才能访问的get请求的第二种实现",httpMethod = "GET")` ### 成功输出效果 ## 6. 返回cookies信息的post接口开发 ### 在Chapter10 中,在包 com.course.server 中新建 MyPostMethod.java,方法同上 ### 成功输出效果 ## 7.Cookies验证和返回用户列表的post接口开发及常见错误解决 ### 在Chapter10 中,新建包 com.course.bean 中pom.xml:引入 `lombok` ; ### 新建 User.java,存储用户信息(userName/password/name/age/sex) ### 在 MyPostMethod.java 中:新建 `public String login(HttpServletResponse response,@RequestParam(value = "userName",required = true) String userName, @RequestParam(value = "password",required = true) String password)`; ### 并添加注解`@RequestMapping(value = "/login",method = RequestMethod.POST)` 和 `@ApiOperation(value = "登陆接口,成功后获取cookies信息",httpMethod = "POST")` ### 验证cookies是否合法:` for(Cookie c : cookies){if(c.getName().equals("login") && c.getValue().equals("true") && u.getUserName().equals("zhangsan") && u.getPassword().equals("123456") )` ## 十、数据持久层框架MyBatis的应用 ## 1. Mybatis和logback的应用配置 ### 新建 Chapter11 ,配置 pom.xml: 引入`spring-boot-starter-web` 、`springfox-swagger-ui`、`springfox-swagger2`、` lombok`、`fastjson`、`mysql-connector-java`、`mybatis-spring-boot-starter` ### 新建配置文件 application.yml;添加配置 server 、logging 、spring 、mybatis; ### 新建配置文件 logback.xml :固定的方式,无需记忆 ### 新建配置文件 mybatis-config.xml:固定的方式,无需记忆 ## 2. 使用mybatis+SpringBoot完成第一个查询demo ### 在 Chapter11 中,新建 mapper 文件夹,在其中新建 mysql.xml 放置数据库的查询信息 ### 数据库内容输出 ### 在 Chapter11 中,新建 com.course 包,在其中新建 Application.java 放置配置文件 ### 在 Chapter11 中,新建com.course.controller 包,在其中新建 Demo.java :写查找数据库内容的执行程序 ### 查询效果展示 ## 3. 使用mybatis实现添加数据和idea的debug操作 ### 在 Chapter11 中,新建 com.course.model 包,新建 User.java : 放置数据 id、name、sex、age ### 在 mysql.xml 中设置 增、删、改、查方法: 1.查 : `` 在 Demo.java 中的 查 方法 `@RequestMapping(value = "/getUserCount",method = RequestMethod.GET) @ApiOperation(value = "可以获取到用户数",httpMethod = "GET") public int getUserCount(){ return template.selectOne("getUserCount"); }` 2.增: ` insert into user(id,name,age,sex),values(#{id},#{name},#{age},#{sex}) ` 在 Demo.java 中的 增 方法 `@RequestMapping(value = "/addUser",method = RequestMethod.POST) public int addUser(@RequestBody User user){ int result = template.insert("addUser",user); return result; }` ### 增加效果展示 3.改 : ` update user set name=#{name},age=#{age} where id=#{id} ` 在 Demo.java 中的 改 方法 `@RequestMapping(value = "/updateUser",method = RequestMethod.POST) public int updateUser(@RequestBody User user){ return template.update("updateUser",user); }` ### 修改效果展示 4.删 : ` delete from user where id = #{id} ` 在 Demo.java 中的 删 方法 `@RequestMapping(value = "/deleteUser",method = RequestMethod.GET) public int delUser(@RequestParam int id){ return template.delete("deleteUser",id); }` ### 删除效果展示 ## 十一、MyBatis+MySQL实现用例管理 ## 1. Case与系统的表结构设计 ### 新建数据库表 :addUserCase 表 ### getUserInfoCase 表: ### getUserListCase 表: ### loginCase 表: ### updateUserInfoCase 表: ### user 表 ## 2. 基础配置文件的设计 ### 新建 Chapter12 ,配置 pom.xml: 引入`httpclient` 、`json`、` mysql-connector-java`、` lombok`、`extentreports`、` testng-extentsreport`、`extentreports` 、`testng`、`commons-logging`; ### 在 Chapter12 中,新建 databaseConfig.xml :配置 SQL 数据库的文件;新建 testng.xml ,配置测试文件的文件;新建 application.properties:设置端口信息、定义各种接口(登陆接口、更新用户信息接口、获取用户列表接口、获取用户信息接口、添加用户接口) ## 3. model层、config层和加载配置文件工具类 ### 在 Chapter12 中,新建 com.course.cases 包, ### 新建 com.course.model 包,在其中新建 User.java:声明User 表信息,将 string 变为 JSON 格式 ### 在com.course.model 包中新建AddUserCase.java:声明AddUserCase表信息 ### 在com.course.model 包中新建GetUserInfoCase.java:声明GetUserInfoCase表信息 ### 在com.course.model 包中新建GetUserListCase.java:声明GetUserListCase表信息 ### 在com.course.model 包中新建UpdateUserInfoCase.java:声明UpdateUserInfoCase表信息 ### 在com.course.model 包中新建LoginCase.java:声明LoginCase表信息 ### 在com.course.model 包中新建InterfaceName.java:声明interface 对应的5个接口 ### 新建 com.course.config 包,新建 ExtentTestNGIReporterListener.java;新建 TestConfig.java: 存放 application.properties 中对应的变量,与配置文件中的接口对应。 ### 新建 com.course.utils包(定义方法),新建 ConfigFile.java : 拼接 URL,定义最终的测试地址;获取直接 bundle.getString( ) 即可;例 `uri = bundle.getString("getUserList.uri");` ## 4. 数据库工具类的创建 ### 在 com.course.utils包(定义方法),新建 DatabaseUtil.java : ### 1.获取配置的资源文件:`Reader reader = Resources.getResourceAsReader("databaseConfig.xml");` ### 2.把该文件 build 出来 `SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);` ### 3.返回sqlSession,sqlSession就是能够执行配置文件中的sql语句。`SqlSession sqlSession = factory.openSession();` ### 在 com.course.cases 包中新建 LoginTest.java/AddUserTest.java/GetUserInfoListTest.java/GetUserInfoTest.java/UpdateUserInfoTest.java :写具体的测试代码。 ### 无异常效果展示 ## 十二、TestNg+MyBatis实现数据校验 ## 1. 基础配置 ### 新建 Chapter13 ,配置 pom.xml: 引入`maven-compiler-plugin` 、`spring-boot-maven-plugin`、`maven-compiler-plugin`、`spring-boot-starter-parent`、`springfox-swagger-ui`、` fastjson`、`mysql-connector-java` 、`mybatis-spring-boot-starter` ; ### 在Chapter13 中,新建 application.yml :添加配置 server(端口) 、logging 、spring(数据库) 、mybatis; ### 新建配置文件 logback.xml :固定的方式,无需记忆 ### 新建配置文件 mybatis-config.xml:固定的方式,无需记忆 ### 在 Chapter13 中,新建 mapper 文件夹,在其中新建 mysql.xml 放置数据库的查询信息 ## 2. 接口代码开发 ### 在Chapter13 中,新建 com.course 包,中新建 application.java 启动类:添加 注解 @EnableScheduling 、@SpringBootApplication; ### 新建 com.course.model 包,中新建 User.java :声明数据 id、userName、password、age 、sex 、permission、isDelete; ### 新建 com.course.config 包,中新建 SwaggerConfig.java :放置Swagger配置文件 ### 新建 com.course.controller 包,中新建 UserManager.java ;定义接口信息:登陆接口 、添加用户接口 、获取用户(列表)信息接口、更新/删除用户接口; 例:`@ApiOperation(value = "登陆接口",httpMethod = "POST") @RequestMapping(value = "/login",method = RequestMethod.POST) public Boolean login(HttpServletResponse response, @RequestBody User user){ int i = template.selectOne("login",user); Cookie cookie = new Cookie("login","true"); response.addCookie(cookie); log.info("查询到的结果是"+i); if(i==1){ log.info("登陆的用户是:"+user.getUserName()); return true; } return false; }` ## 3. mapper开发及自测接口 ### 在 mysql.xml :写各接口的 sql 语句 ;登陆接口sql 、 添加用户接口sql 、获取用户sql 、 更新/删除用户信息sql 登陆接口sql: 例:` ` 获取用户sql : ### 自测试效果展示 ## 4. 自动化测试代码开发 ### 在 Chapter12 中,在包 com.course.cases 中的 AddUserTest.java 中:写发送请求、获取结果和验证表单结果功能; 发送请求、获取结果: `String result = getResult(addUserCase);` `User user = session.selectOne("addUser",addUserCase);` 验证表单结果:`Assert.assertEquals(addUserCase.getExpected(),result);` 设置头信息 :`post.setHeader("content-type","application/json");` 设置cookies:`TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);` ### 在包 com.course.cases 中的 LoginTest.java 中 :写用户登录测试功能: 定义测试方法:`@BeforeTest(groups = "loginTrue",description = "测试准备工作,获取HttpClient对象")` 、`@Test(groups = "loginTrue",description = "用户登陆成功接口测试")`、`@Test(groups = "loginFalse",description = "用户登陆失败接口测试")` 第一步就是发送请求:`String result = getResult(loginCase);` 第二步验证结果:` Assert.assertEquals(loginCase.getExpected(),result);` ### 自测试效果展示 ### 在包 com.course.cases 中的 GetUserInfoListTest.java 中 : 发送请求:`JSONArray resultJson = getJsonResult(getUserListCase);` 验证结果:`List userList = session.selectList(getUserListCase.getExpected(),getUserListCase);`/` Assert.assertEquals(userListJson.length(),resultJson.length());` ### 在包 com.course.cases 中的 GetUserInfoTest.java 中 : 发送请求: `JSONArray resultJson = getJsonResult(getUserInfoCase);` 验证结果:`Assert.assertEquals(jsonArray.toString(),jsonArray1.toString());` ## 5. 常见问题及解决 ### 自测试效果展示 1.在包 com.course.cases 中的 AddUserTest.java 中 :`User user = session.selectOne("addUser",addUserCase);` 没有查询到结果 原因分析:` String result = getResult(addUserCase);` 调取接口需要时间 解决方法:添加 `Thread.sleep(5000);` 2.在包 com.course.cases 中的 GetUserInfoTest.java 中:`Assert.assertEquals(jsonArray,resultJson); ` 返回顺序不同 原因分析:值完全一样,判断相等却失败(转换成 String ) 解决方法:修改为: `JSONArray jsonArray = new JSONArray(userList);` `JSONArray jsonArray1 = new JSONArray(resultJson.getString(0));` `Assert.assertEquals(jsonArray.toString(),jsonArray1.toString());` ### 自测试效果展示 ## 十二、持续集成 ## 1. 打包配置 ### 在 Chapter12 ,配置 pom.xml: 引入插件 ` org.apache.maven.plugins maven-surefire-plugin 2.7.1 ./src/main/resources/testng.xml ` 打包指令:mvn clean package (cmd 中输入)【清除整个过程】 ### 接口打包配置: ### 在 Chapter13 ,配置 pom.xml: ## 2. jenkins环境搭建 1.下载 jenkins.war 2.运行 jenkins.war 3.运行成功 4.安装插件 ## 3. Jenkins任务配置 1.建立 deploy ,配置 1.建立 test ,配置 ## 4.Jenkins任务执行 ### 运行 Jenkins ### 测试成功 ## 5.在线报告维护小系统的搭建 ### 修改 deploy 配置 ### 启动 Tomcat ### 输出测试报告 ## 十三、总结 ### 问题:你的自动化测试是怎么做的? ### 回答1. 项目维度的推进方式 ### 项目整体阶段 ### 需求阶段 ### 开发阶段 ### 测试阶段 ### 上线回归 ### 回答2. 技术落地方案 ### 本项目技术框架 ### 自动化测试的好处 ### 1.手动测试变为自动测试:一个测试用例的时间极大缩短,极大减少测试时间 ### 2.测试工作由“重后期”变为“重前期”:与开发的重点在同一阶段,缩短项目开发时间 ### 3.项目流程由串行变为并行 :项目流程优化,缩短项目开发时间 ### 4.测试数据共享可不断积累、降低漏测率:用例持久化的优点 ### 5.测试报告可管理、可追溯、可查询:使用 ExtentReport 的优点 ### 6.Mock 平台可将集成环节提前,降低集成成本