为了账号安全,请及时绑定邮箱和手机立即绑定
2.1 适合采用自动化测试

考虑否采用自动化测试,需要从三个方面进行权衡:软件需求变动不频繁测试脚本的稳定性决定了自动化测试的维护成本。如果软件需求变动过于频繁,测试人员需要根据变动的需求来更新测试用例以及相关的测试脚本,而脚本的维护本身就是一个代码开发的过程,需要修改、调试,必要的时候还要修改自动化测试的框架。如果开发、维护测试脚本的成本高于利用其节省的测试成本,即投入产出比太高,那么自动化测试就失去了意义。项目中的某些模块相对稳定,而某些模块需求变动性很大。我们便可对相对稳定的模块进行自动化测试,而变动较大的仍是用手工测试。项目周期足够长软件测试包含有如下环节:自动化测试需求的确定自动化测试框架的设计自动测试脚本的编写与调试这样的过程本身就是一个测试软件的开发过程,需要较长的时间来完成。如果项目的周期比较短,没有足够的时间去支持这样一个过程,则无法实施自动化测试。自动化测试脚本可重复使用通常情况下,专职的测试人员对多个产品进行测试,需要考虑自动化测试脚本能否重复使用:所测试的项目之间是否很大的差异性所选择的测试工具是否适应这种差异如果测试脚本的重复使用率很低,致使其间所耗费的成本大于所创造的价值,自动化测试就失去了意义。敏捷开发、频繁的版本迭代敏捷开发,增量式开发,持续集成项目由于这种开发模式是频繁的发布新版本,需要频繁的回归测试,自动化能把能从回归测试中解脱出来测试新的功能。

1. PyCharm 支持的测试框架

测试框架可以组织、管理和执行那些独立的自动化测试用例,测试完成后统计测试结果。PyCharm 支持主流的测试框架,如图所示:前三种框架用的比较多,特别是 Pytest 近几年是比较流行的,经常与 request + Allure 搭档用于接口的自动化测试。另外,在基于业务驱动软件公司, BDD 测试框架应用也越来越广泛。大家可以根据自己的实际环境与需求所择合适的测试框架,有关安装及其它更详细信息,请参阅对应的框架文档。 图片来源:https://www.jetbrains.com/help/pycharm/testing-frameworks.htmlTips:在开始使用您选择的测试框架之前,请确保在计算机上安装了所需的框架。

2.3 测试

我们在项目中与 main 目录同级的 test 目录中找到测试类 ZkClientDemoApplicationTests ,在其中添加测试方法。2.3.1 查询测试package cn.cdd.zkclientdemo;import cn.cdd.zkclientdemo.service.ZkClientServer;import org.I0Itec.zkclient.ZkClient;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTestclass ZkClientDemoApplicationTests { // 依赖注入 @Autowired private ZkClientServer zkClientServer; @Test void contextLoads() { // 获取 ZkClient 对象 ZkClient zkClient = zkClientServer.getZkClient(); // 获取子节点集合 List<String> children = zkClient.getChildren("/"); System.out.println(children); // 释放资源 zkClient.close(); }}执行测试方法,控制台输出:[zookeeper, imooc]我们可以看到控制台输出了在上一节中我们增加的节点 imooc,说明我们的查询成功执行了。接下来我们测试其它的 API。2.3.2 创建持久节点创建持久节点测试:@Testvoid contextLoads() { ZkClient zkClient = zkClientServer.getZkClient(); // 在 imooc 节点下创建持久节点 wiki zkClient.createPersistent("/imooc/wiki"); // 获取 imooc 节点的子节点集合 List<String> children = zkClient.getChildren("/imooc"); System.out.println(children); // 释放资源 zkClient.close();}执行测试方法,控制台输出:[wiki]2.3.3 删除节点删除节点测试:@Testvoid contextLoads() { ZkClient zkClient = zkClientServer.getZkClient(); // 删除 imooc 的 子节点 wiki boolean delete = zkClient.delete("/imooc/wiki"); System.out.println(delete); // 释放资源 zkClient.close();}执行测试方法,控制台输出:truetrue 表示删除 wiki 节点成功。2.3.4 读写数据节点数据读写测试:@Testvoid contextLoads() { ZkClient zkClient = zkClientServer.getZkClient(); // 给 imooc 节点写入数据 wiki zkClient.writeData("/imooc","wiki"); // 读取 imooc 节点的数据 Object data = zkClient.readData("/imooc"); System.out.println(data); // 释放资源 zkClient.close();}执行测试方法,控制台输出:wikiTips: 当我们使用 API 操作节点时,节点参数必须是全路径。测试完成后,我们来对 ZkClient 常用的 API 做一下介绍。

2.4 执行测试

通常,PyCharm 通过运行已创建的运行/调试配置,以与其他应用程序相同的方式运行和调试测试。在许多情况下,也可以从上下文菜单启动测试会话,如果运行的测试没有永久运行/调试配置,则创建临时配置。然后,如果以后要重用,可以使用"运行/调试配置"对话框保存此类配置。1. 下面演示了不同运行路径,可运行整个模块,也可以运行单个方法。在 Run 工具 窗口内可以看到运行结果。工具窗口与通用的 Run 窗口基本一致,但会多一些为测试所加的工具按钮。2. 可以通过 Run 工具栏中 Rerun 与 Rerun Failed Tests 重新运行用例:3. PyCharm 可以设置自动重新运行测试的运行/调试配置(如果源代码已更改)。点击 Run 工具栏中的 Toggle auto-test 按钮该功能生效。下面只单独运行 test_area 这个方法,按下 Toggle auto-test,然后简单修改这个方法,会看到测试被自动执行了。

1.2 自动化测试

自动化测试是通过编写脚本的方式模拟手工测试的过程。通过运行脚本来执行测试用例,代替人工对系统的功能进行验证,从而节省了大量的人力。一切通过工具的方式来代替或辅助手工测试的行为都可以看做自动化,包括性能测试、接口测试等,但凡用到测试工具的测试都称为自动化测试。自动化测试得到广泛的应用,在招聘测试职位时,都需要自动化测试经验。在计算机专业招聘网站,以 “自动化测试” 作为关键字进行搜索,能够搜索到大量的职位,如下图所示:

2.5 测试

为了充分理解缓存的含义,我们通过测试类发起测试。实例:@SpringBootTestclass SpringBootCacheApplicationTests { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private CacheManager cacheManager; @Autowired private GoodsService goodsService; // 显示当前使用的缓存管理器类型 @Test void showCacheManager() { // 输出:org.springframework.cache.concurrent.ConcurrentMapCacheManager logger.info(cacheManager.getClass().toString()); } // 缓存测试 @Test void cacheTest() { // 第一次执行,没有缓存,执行方法体 goodsService.getById(1L); // 再次执行,直接取出缓存,不执行方法体 goodsService.getById(1L); // 移除缓存 goodsService.remove(1L); // 再次执行,已经没有对应缓存,所以执行方法体 GoodsDo oldGoods = goodsService.getById(1L); // 打印缓存内容 logger.info("old goods id:{} name:{}", oldGoods.getId(), oldGoods.getName()); // 更新缓存 GoodsDo temp = new GoodsDo(); temp.setId(1L); temp.setName("新的商品"); goodsService.edit(temp); // 查询并打印已更新的缓存内容 GoodsDo newGoods = goodsService.getById(1L); logger.info("new goods id:{} name:{}", newGoods.getId(), newGoods.getName()); }}我们查看下控制台输出如下,验证了我们设计的缓存机制。使用 Spring Boot 默认缓存时控制台输出内容

2.6 测试

通过测试类发起测试,此处我们简单执行 1000 次插入,看看执行时间。需要注意的是,Spring Boot 进行测试时,需要添加注解 @SpringBootTest 。添加注解后该类可以直接通过 @Test 标注的方法发起单元测试,容器环境都已准备好,非常方便。实例:@SpringBootTest // 通过该注解,开启测试类功能,当测试方法启动时,启动了Spring容器class SpringBootHikariApplicationTests { @Autowired private DataSource dataSource;// 自动注入数据源 @Autowired private GoodsDao goodsDao; /** * 打印数据源信息 */ @Test // 测试方法 void printDataSource() { System.out.println(dataSource); } /** * 批量插入测试 */ @Test void insertBatch() { // 开始时间 long startTime = System.currentTimeMillis(); // 执行1000次插入 GoodsDo goods = new GoodsDo(); goods.setName("测试"); goods.setPic("测试图片"); goods.setPrice("1.0"); for (int i = 0; i < 1000; i++) { goodsDao.insert(goods); } // 输出操作时间 System.out.println("use time:" + (System.currentTimeMillis() - startTime)+"ms"); }}输出结果如下,可见默认数据源类型为 HikariDataSource ,插入 1000 条数据的时间大概为 1500ms (注意时间可能跟电脑性能等很多因素相关,此处只是进行简单的对比测试)。use time:1518mscom.zaxxer.hikari.HikariDataSource

2.1 指定测试用例进行测试

其实每一项新的操作一般都会伴随一些问题产生。例如,我们在实际的开发过程中,有些时候只是改动了一处代码,但是如果直接执行 mvn test 命令的话,会将整个项目的测试用例全部都执行一遍,这对于我们来说,是有些得不偿失的,没必要因为一处改动,而去测试其他几十个或者几百个测试用例。那我们应该怎么办呢? 这里我们为了演示,写了两个测试类,OrderServiceTest 和OrderService2Test,其中第一个类中,有两个测试用例,第二个类中,只有一个测试用例。这时候,我们修改了第二个类中测试用例对应的方法,需要重新进行单元测试。我们可以直接执行命令:mvn test -Dtest=OrderService2Test:[INFO] Scanning for projects...[INFO][INFO] ----------------------< com.mic.tech:mall-order >-----------------------[INFO] Building mall-order 1.0.0-SNAPSHOT[INFO] --------------------------------[ jar ]---------------------------------[INFO] ...[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ mall-order ---[INFO] Surefire report directory: D:\code\mall-aggregate\mall-order\target\surefire-reports------------------------------------------------------- T E S T S-------------------------------------------------------Running com.mic.tech.OrderService2Test...Results :Tests run: 1, Failures: 0, Errors: 0, Skipped: 0[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 4.261 s[INFO] Finished at: 2020-05-21T22:17:47+08:00[INFO] ------------------------------------------------------------------------从结构来看,我们这里只执行了第二个测试类中的测试用例。

2.5 并发访问测试

我们通过测试类发起并发访问测试,代码如下:实例:/** * 访问统计服务测试 */@SpringBootTestclass VisitServiceTest { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private VisitService visitService; @Test void test() { logger.info("访问次数:{}", visitService.getCurrentCount()); // 使用线程池快速发起10000次访问 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10000; i++) { cachedThreadPool.execute(new Runnable() { public void run() { visitService.addCount(); } }); } }}此时我们通过 Redis 客户端发现 visit_count 的值如下:并发访问测试结果Tips:Redis 中的操作都是原子性的,要么执行,要么不执行,在高并发场景下依然可以准确的进行计数,关键是速度还非常之快!

5. 测试

我们直接编写测试类,对数据访问接口进行测试。此处通过 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 注解,使测试方法按名称顺序依次执行。这样就可以一次性测试 GoodsDao 中的所有方法了,具体测试代码如下:实例:/** * GoodsDao测试类 */@SpringBootTest@FixMethodOrder(MethodSorters.NAME_ASCENDING) // 按方法名称顺序测试class GoodsDaoTest { @Autowired private GoodsDao goodsDao; /** * 新增一个商品 */ @Test void test_01() { GoodsDo goods = new GoodsDo(); goods.setName("手机"); goods.setPic("phone.jpg"); goods.setPrice("2000"); int count = goodsDao.insert(goods); assertEquals(1, count);// count值为1则测试通过 } /** * 更新商品信息 */ @Test void test_02() { GoodsDo goods = new GoodsDo(); goods.setId(1L); goods.setName("手机"); goods.setPic("phone.jpg"); goods.setPrice("3000"); int count = goodsDao.update(goods); assertEquals(1, count);// count值为1则测试通过 } /** * 获取商品信息 */ @Test void test_03() { GoodsDo goods = goodsDao.selectOne(1L); assertNotNull(goods);// goods不为null则测试通过 } /** * 删除商品 */ @Test void test_04() { int count = goodsDao.deletex(1L);//此处应为delete(1L) assertEquals(1, count);// count值为1则测试通过 } /** * 获取商品信息列表 */ @Test void test_05() { List<GoodsDo> goodsList = goodsDao.selectAll(); assertEquals(0, goodsList.size());// goodsList.size()值为0则测试通过 }}测试结果如下,说明所有测试都通过了。JUnit 测试结果

5. 测试脚本

你还可以用 JavaScript 为 Postman API 请求编写测试脚本。测试脚本能确保你的请求按预期工作,确保后台服务之间的集成运行可靠,验证新开发的功能没有破坏之前已存的功能。当 API 出现问题时,还可以使用测试脚本帮你调试程序。比如,你可以编写一个测试脚本,通过发送不完整的数据给请求来验证请求的错误处理。可以向单个请求、文件夹和集合添加测试脚本。Postman 里包含一些脚本你可以通过点击来增加,然后根据需求来修改里面的逻辑。要给请求添加测试代码,跟上面添加“请求前脚本”一样,打开请求,并在 “Tests” 选项卡中添加代码。在 “Test Results” 选项卡中看到输出。

4.1 PyUnit 单元测试框架

PyUnit 是 Python 内置的 Python 单元测试框架(The Python unit testing framework),可对程序中的最小可测试单元进行检查和验证。它的主要特点如下:内置的标准模块,在 Python 3 中,PyUnit 是标准模块,安装 Python 后引入 unittest 模块即可使用PyUnit 是 JUnit 的衍生产品,其工作原理与其他 JUnit 框架十分类似,熟悉 JUnit 的开发者可以很快上手能够以简单的方式运行单个测试用例能够快速的生成各种测试报告PyUnit 是 Kent Beck 和 Erich Gamma 设计的 JUnit 的 Python 版本,是 JUnit 的衍生产品,在工作原理、命名规则上保留了很多 Java 语言的特征。例如,PyUnit 要求所有的测试用例都必须继承于 TestCast,示例如下:#!/usr/bin/python3import unittestdef add(a, b): return a + bdef sub(a, b): return a - bclass MathTest(unittest.TestCase): def testAdd(self): self.assertEqual(add(1, 1), 2) def testSub(self): self.assertEqual(sub(2, 1), 1)unittest.main()定义了类 MathTest,继承于 unittest.TestCase定义了测试用例 testAdd,测试函数 add定义了测试用例 testSub,测试函数 sub

4.4 Selenium Web 应用程序测试

Selenium 是一个用于 Web 应用程序测试的工具,它使用 JavaScript 模拟真实用户对浏览器进行操作。Selenium 支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。Selenium 支持使用 Python 语言编写动作测试脚本,测试脚本执行时,浏览器自动按照脚本代码做出点击、输入、打开、验证等操作,就像真实用户所做的一样,从终端用户的角度测试应用程序。用户使用 Python 编写测试脚本:测试应用程序的浏览器兼容性,验证应用程序是否能够工作在不同浏览器和操作系统之上创建回归测试检验软件功能和用户需求Selenium 主要用于测试 Web 应用程序,学习 web 自动化测试前,需要补充 Web 相关的知识,包括:HTTP 协议HTML 的基础知识,如何使用 Javascript 操纵 DOMFirebug 或者 Chrome 开发者工具的使用,用于抓取元素

2.2 不适合采用自动化测试

如果项目具备如下特征,则不适合做自动化测试:被测系统或需求不稳定在自动化测试用例的更新、维护、调试的频率太高,自动化测试完全得不偿失。项目时间非常紧张建自动化测试框架,开发测试脚本需要时间,对时间比较紧张的项目可以先不考虑自动化。项目周期很短测试脚本不能得到重复的利用,不值得花精力去进行自动化测试。涉及人的感观、物理交互等方面的测试易用性测试、需要人的主观判断,涉及物理交互,自动化工具无法完成与物理设备的交互,例如打印、摄像等操作,不适合采用自动化测试。

3.5 自动化测试

自动化测试,顾名思义是指自动完成测试工作。通过工具模拟人工的操作过程,并验证其结果,这样的测试过程,就是是自动化测试。自动化测试节约了批人力成本,让机器执行大量的重复繁琐的劳动。Python 提供了众多的自动化测试框架,可以实现:单元测试:简化单元测试的编写。对 GUI 程序的自动化测试:Python 提供了模拟鼠标的单击和移动、键盘输入等功能,模拟用户操作 GUI 程序。Web 自动化测试:Python 提供了模拟鼠标的单击和移动、键盘输入等功能,模拟用户操作浏览器。性能测试:使用代码模拟大批量用户,让用户并发请求,统计系统负载能力并生成报告。

3. 测试报告

Maven 的默认配置中,会在 target\surefire-reports 目录下生成测试报告。我们执行 mvn clean test,就可以观察到该目录生成。我们可以在 txt 格式的文档中看到生成的测试报告。这里的测试报告基本上和控制台输出的内容是类似的。大家可能也注意到了,我们在执行测试用例的时候,同时生成了两种类型的文件,一种是 txt 格式,另一个则是 XML 格式。txt 格式: 为了让执行测试用例的开发者更加直观的看到测试用例的运行结果;XML格式: 更多的是为了支持其他工具的解析。

1.1 手工测试

手工测试是由人逐个的输入测试用例,然后观察程序运行结果,和预期结果进行比对。人工测试是一种低效的测试方法,对程序进行修改后,都需要人工重新执行测试用例,属于典型的重复劳动。根据 51testing 的《中国软件测试从业人员调查报告》,在软件项目的测试环节,手工测试占到 89%,相对开发来说,测试的门槛底,薪资普遍较底,所要求的知识面虽然有一定广度,但缺乏深度。因为手工测试人门槛不高,使大量的毕业生、甚至是非专业人员涌入这个行业,从而加剧了这个行业的激烈竞争。对于工作几年仍处于手工测试的人员来说,都会有强烈的危机感。由于工作的技术含量不高,薪资的涨幅遇到瓶颈,另一方面受到新进入者的威胁,公司花 5K 招来的人能够胜任测试工作,那么就不会花 8K 招聘人做同样的工作。因此,从自身的发展来说,测试人员非常需要通过自动化技术来增加自己有竞争力。

6. 编写测试脚本

测试脚本会在 API 收到响应之后执行。要验证返回的结果是否正确,你可以使用 pm.response 对象。可以使用 pm.test 方法,提供一个名称和函数,该函数会返回一个布尔值(true 或者 false) 指示测试时成功还是失败。还可以在断言中使用 ChaiJS BDD 语法和 pm.expect 来测试响应细节。pm.test 的第一个参数用来标识这个测试脚本,会出现在测试结果输出中。例如,在 “Tests” 选项卡中为任一请求输入一下内容,以测试响应状态代码是否为200。pm.test("Status test", function () { pm.response.to.have.status(200);});点击“发送”运行请求,并在响应部分打开 “Test Results” 选项卡,在选项卡标题中显示了运行了几个测试有几个通过了。代码还可以测试请求环境,如下所示:pm.test("environment to be production", function () { pm.expect(pm.environment.get("env")).to.equal("production");});pm.test("response should be okay to process", function () { pm.response.to.not.be.error; pm.response.to.have.jsonBody(""); pm.response.to.not.have.jsonBody("error");});使用定制响应数据格式的语法来验证请求响应的有效性:pm.test("response must be valid and have a body", function () { pm.response.to.be.ok; pm.response.to.be.withBody; pm.response.to.be.json;});测试脚本可以包含任意数量的测试,当点击保存的时候,测试脚本会随请求详情一起被保存。

4.3 测试

由于之前已经通过注解 @EnableCaching 开启了缓存功能,此时我们直接运行测试类进行测试,输出结果如下:使用 Redis 缓存时控制台输出内容从上图输出结果可以看出,已经成功使用了 Redis 缓存管理器。另外我们可以直接使用 Redis 客户端查看生成的缓存信息,如下图已经有名为 GoodsCache::1 的缓存键存在了。Redis 客户端查看缓存信息

4.3 Robot 测试框架

Robot Framework 是一个基于 Python 的,可扩展的关键字驱动的测试自动化框架,主要被用在测试驱动 (test-driven)类型的开发与验收中。Robot Framework 具有高度模块化的架构,用户通过编写 Python 脚本扩展功能,如下图所示:测试数据 (Test Data) 是简单、易于编辑表格格式启动 Robot Framework 时,它会处理测试数据,执行测试用例并生成日志和报告测试库 (Test library) 可以直接使用应用程序接口Robot Framework 具有如下优点:通过使用关键字驱动测试的方法,帮助测试人员创建具有可读性的测试用例,进而简化了整个自动化的过程。启用易于使用的表格语法,以统一的方式创建测试用例。提供易于阅读的结果报告和 HTML 格式的日志。提供一个简单的库 API,可以使用 Python 创建自定义测试库。

4.2 PyTest 测试框架

Pytest 是一个第三方单元测试框架,比内置的 PyUnit 更简洁和高效,Pytest 主要特点有以下几点:简单灵活,容易上手,测试的可读性强支持参数化,可以细粒度地控制要测试的测试用例能够支持单元测试、集成测试、功能测试、接口测试多种类型Pytest 具有丰富的第三方插件,并且可以自定义扩展,例如如 pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)等可以很好的和 CI 工具结合,例如 jenkins与其它测试框架相比 Pytest 简单易学,举例如下:def add(a, b): return a + bdef sub(a, b): return a - bdef test_add(): assert add(1, 1) == 2def test_sub(): assert sub(2, 1) == 1定义了函数 test_add,它测试函数 add 的功能定义了函数 test_sub,它测试函数 sub 的功能运行 pytest ,发现所有名称以 test_ 为前缀的函数、并运行凭借着其开源和易学的特点,该工具被质量分析团队、开发团队、个人团队、以及各种开源项目广泛使用。许多大型互联网应用,如 Dropbox 和 Mozilla,均采用 Pytest。

4. 测试

我们主要是测试 JPA 模块正确可用,所以直接在测试类发起对 IGoodsDao 方法的测试即可。

3.3 使用 Swagger2 进行接口测试

此时我们启动项目,然后访问 http://127.0.0.1:8080/swagger-ui.html ,即可打开自动生成的可视化测试页面,如下图。Swagger2 自动生成可视化测试界面嗯,感觉这个页面简单整洁,直接给测试人员使用都很方便。我们以 update 方法为例演示下如何测试。先看看该方法的代码:实例: /** * 修改商品 */ @PutMapping("/goods/{id}") public void update(@PathVariable("id") long id, @RequestBody GoodsDo goods) { // 修改指定id的商品信息 goods.setId(id); goodsService.editGoods(goods); }测试时先选中对应的方法 update , 然后点击 Try it out 开始测试。Swagger2 生成的测试方法在参数区域输入 id 和 goods 的值。Swagger2 可视化测试参数输入点击 Execute 后,返回 Code 为 200 表示 http 请求成功!Swagger2 可视化测试结果输出由此可见, Swagger2 将接口以可视化的方式呈现出来,开发人员不必手输接口地址、参数名称,就可以发起测试并查看结果,确实非常方便。后端人员在开发完成后,可以自己使用 Swagger2 测试下接口可行性。而前端人员也可以打开 Swagger2 网页直接验证接口功能。

在 PyCharm 里执行测试

在实际工作学习中,在我们编写代码,经过调试与运行,完成预设的功能后,许多时候我们还需要编写测试代码去测试刚刚完成的功能。测试代码的编写与执行一般都基于一些成熟的测试框架,在框架内调用待测代码方法,进行断言判断来验证待测代码是否完成期望功能。本节主要讲述在 PyCharm 内创建测试与执行测试的步骤,以及其中提供的一些主要功能。

2. 计算文本宽度

canvas 为我们提供了一个计算文本宽度的方法:measureText 方法,方法返回一个 TextMetrics 对象,包含关于文本尺寸的信息,里面就有文本宽度。我们看一个案例:1499运行结果:上面案例中,我们封装了一个函数,可以绘制自适应大小的按钮,让我们拆分讲解一下主要代码。先看绘制按钮的封装函数 drawBtn,函数传入了三个参数,分别是绘制文本以及绘制文本的起点坐标 (x, y)。function drawBtn(str, x, y ){ ...}(1)获取到绘制文本的宽度和高度,其实文本的高度就是设置的文本字体的大小值,这里我们用了一个小技巧拿到了设置的文本大小。 var w = ctx.measureText(str).width; // 获取到绘制文本的宽度w var h = parseInt(ctx.font) // 通过小技巧获取到了文本高度h(2)设置按钮背景为 #456795 这个颜色,并且绘制了一个矩形,这里矩形坐标我们向左上方移动了10个像素,目的是给按钮添加一个内边距,美观一些,因为左侧有10个像素边距,右侧也有10个像素边距,所以我们给背景的矩形框的长度增加了20个像素,高度同理,也增加了20个像素。 ctx.fillStyle="#456795"; ctx.fillRect(x-10,y-10,w+20,h+20)(3)设置文字的颜色为白色,把文字的基线设置为 hanging,这样做的目的是将文本左上角和基线对齐,方便计算,我们也可以设置为其他值,不过计算起来会比较麻烦。 ctx.fillStyle="#fff"; ctx.textBaseline="hanging"(4)绘制文本。 ctx.fillText(str,x,y)设置字体大小为16像素,调用封装函数绘制文字。 ctx.font="16px 微软雅黑"; drawBtn("慕课Wiki",40,40)设置字体大小为18像素,调用封装函数绘制文字。 ctx.font="18px 微软雅黑"; drawBtn("Imooc教程 Hello World", 40, 90)设置字体大小为20像素,调用封装函数绘制文字。 ctx.font="20px 微软雅黑"; drawBtn("确认", 40, 140)

2.2 创建测试

创建一个新的 Python project,增加新文件 rectangle.py,添加下面的代码到文件, 继续沿用上一小节用到的待测代码。import mathclass Rectangle: def __init__(self, length, width, size=(40, 20)): self.length = length self.width = width self._size = size def area(self): area = self.length * self.width return area def perimeter(self): perimeter = (self.length + self.width) * 2 return perimeter def diff(self): diff = math.fabs(self.length - self.width) return diff def resize(self, width, height): if width <= 0 or height <= 0: raise ValueError("illegal size") self._size = (width, height) def get_length(self): return self.length def get_width(self): return self. width在编辑器中,将光标放在类声明或方法中的位置。从主菜单中,选择 Navigate -> Test。编辑器内,右键上下文菜单中选择 Go to -> Test (⌘⇧T: Ctrl + Shift + T)PyCharm 显示可用测试的列表。单击"创建新测试"。在打开 Create test 对话框中进行设置, 点击 OK 会自动生成测试文件 test_rectangle 与 测试方法模板。生成的模板 如下图所示: 没有像 unittest 那样创建同名测试类,无需像导入 unittest 一样导入pytest , 断言直接用 assert。使用pytest 写测试用例看上去更简单一些。

5.1 未登录测试

在未登录时,直接访问控制器方法,会自动跳转 /notLogin 访问路径,返回未登录提示信息。未登录测试

2.2 创建测试

准备一个简单的待测试类,创建新文件 rectangle.py,添加下面的代码到文件import mathclass Rectangle: def __init__(self, length, width, size=(40, 20)): self.length = length self.width = width self._size = size def area(self): area = self.length * self.width return area def perimeter(self): perimeter = (self.length + self.width) * 2 return perimeter def diff(self): diff = math.fabs(self.length - self.width) return diff def resize(self, width, height): if width <= 0 or height <= 0: raise ValueError("illegal size") self._size = (width, height) def get_length(self): return self.length def get_width(self): return self. width在编辑器中,将光标放在类声明或方法中的位置。从主菜单中,选择 Navigate -> Test;编辑器内,右键上下文菜单中选择 Go to -> Test (⌘⇧T: Ctrl + Shift + T);PyCharm 显示可用测试的列表。如果所需的测试尚不存在,请单击"创建新测试"。在打开 Create test 对话框中进行设置, 点击 OK 会自动生成测试文件与测试类。当你创建了测试后,在测试文件可以通过上下文菜单跳到源程序 Go To -> Test Subject,完成测试文件到源文件切换,反之也可以的通过 Go To -> Test 跳回到测试程序。下面的过程演示了创建测试以及测试文件与源文件的切换过程。

3.6 测试

测试类代码同 spring-boot-hikari 一致,运行测试类后,结果如下:use time:1428mscom.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper

2.7 系统测试

系统测试部分多以列表及表格为主。实例 7:# 第五章 系统测试## 5.1 功能点完成情况对照- [x] 数据库创建- [x] 后端开发- [x] 前端开发- [x] 接口联调- [ ] 日志归档## 5.2 测试结果| 功能点 | 是否测试 | 是否通过 | 备注 || ------------ | ---------------------------- | ---------------------------- | ---- || 登录 | <font color="green">√</font> | <font color="green">√</font> | 无 || 登出 | <font color="green">√</font> | <font color="red">×</font> | 无 || 增加学员信息 | <font color="red">×</font> | <font color="red">×</font> | 无 |其渲染效果如下:

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号