一.测试驱动的开发(TDD)
1.定义
- 先开发测试用例,再编写应用程序代码,用于驱动软件设计。
2.步骤:
- ①创建测试场景 编写测试用例
- ②编写应用程序代码
- ③运行测试 若失败则重复②③ / 若成功则④
- ④重构应用程序代码
3.TDD 优点
- 调试时间减少:代码根据定义的测试用例开发。
- 灵活、可维护和可扩展的代码:采用此技术开发的软件是松散耦合且可轻松维护的。
- 关键分析和设计:设计了测试场景并编写了测试用例时才开发代码。
- 可执行文档:测试用例可由其他程序员参考,以了解代码用法及其用途。
- 面向用户的开发:测试用 例是从用户角度编写的。
4.有效测试的准则
- 识别并测试方法的 边界条件,因为方法实际上是在其边界值上生成意外结果。
- 验证 测试结果,因为还要预料得到不正确的结果。
- 了解意外问题,借助模拟对象 模拟这些错误 并将它们注入代码。
- 通过不同策略 交叉检查 测试用例的结果。
- 应用程序代码应该进行良好 优化 以处理大型复杂值,并且必须始终返回准确结果。
5.有效测试的属性
- 自动: 单元测试应该 自动运行,并且没有任何外部依赖,所有连接和配置应该由测试完成。
- 彻底: 测试用例应该覆盖代码的所有方面并提供 100% 的代码覆盖率。
- 独立: 测试用例应该是 独立 于其他测试用例并且松散耦合的。不得对其他测试用例或者类具有任何依赖。
- 专业: 测试应该符合生产 标准 并且代码应该发送给生产服务器。
- 可重复: 测试用例应该是 可重复的,并且在执行时生成同样结果。
6.常见编程问题
- 不可忽视中断失败的测试用例
- 如果代码处理小数值,那么应该总是使用浮点数对它进行测试
- 避免测试用例长时间运行
- 创建低耦合的测试用例
- 测试应该总是生成同样结果,无论在什么机器上执行
- 不要将任何类型的生产代码或者配置代码放到 main() 方法中
二.连续集成测试(CI)及使用 Jenkins
1.基本概念
CI 测试:应用程序将以一定的时间间隔彼此集成,以验证整体功能和稳定性。
CI 测试优点:
- 提供便捷的单元集成
- 允许自动部署
- 提供项目的运行状况报告
- 实现独立于平台的开发
- 提供项目的更好可视性
实现 CI 连续集成测试的工具(独立平台):
- Hudson
- Jenkins
一些 CI 杂谈:
- CI 测试是一种软件开发做法,团队成员 频繁集成工作 以加速调试过程。
- 连续集成测试方法开发的应用程序将更稳定可靠,因为应用程序的模块将 定期 进行集成。
- CI 测试能连续集成应用程序单元并在开发的 早期阶段 识别问题。
- CI 测试能在指定时间后 自动 部署模块。
- CI 测试可以生成项目的 运行状况报告。
- CI 测试提供了环境以在 不同平台上 集成和测试模块。
2.Hudson 简介
简介:Hudson 运行在 Glassfish 或 Apache Tomcat 之类的服务器上,可执行 Ant 和 Maven 项目。
优点:可轻松安装,通过 基于WEB 的 UI 配置,跟踪 jar 文件及其版本。
执行构建后操作:
- 生成 JUnit 测试结果报告:以 .xml 格式保存到指定路径。
- 发送电子邮件通知:向开发人员发送电子邮件通知不稳定的工作版本。
3.Jenkins 简介
- Jenkins 起初作为 Hudson 项目开发,和 Hudson 简介基本相同,但是比 Hudson 有更多的更新和补丁。
- 要启动 Jenkins,需要访问位于端口 8080 的 localhost 服务器。
- Jenkins 能将所有模块组合到一个中央储存库并将它们构建在一起。
- 分析工作版本状态图标:
- 分析工作版本稳定性图标:
- 注册:
- 使用 Jenkins 构建项目,需要配置 JDK、Ant 和 Maven 路径:
- 在 Jenkins 上执行 CI 测试,执行以下步骤:
- 1. 创建新项。
- 2. 配置该项(见下图构建触发器 Build Triggers)。
- 1+2.上面两步创建了项目,显示:
- 3. 创建工作空间(在 Jenkins 安装文件夹中寻找 workspace)。
- 4. 将文件复制到此工作空间(将 IDE 上的项目源文件复制到 Jenkins 安装处的 workspace)。
- 常用的构建触发器是:
- 在其他项目构建之后构建 / 定期构建:
- 不断循环构建,时间设置:
默认情况下, Jenkins 抽取到当前用户的 .jenkins 文件夹。
三.综合测试
四.课堂记录
- 5:00 STLC(Software Testing Life Cycle),其中“缺陷修正”和“测试执行”是一个多次往复的过程,如果这个循环一直有,说明软件代码质量很差,如果这个过程几乎没有,不能说明代码就是一点缺陷也没有,这种情况下,我们往往会认定为:测试人员的测试出现了问题,不能有效的发现BUG
- 7:50 测试环境的搭建也是一门艺术,需要保证被测试软件运行的环境应该能够模拟开发环境和生产环境。生产环境:顾名思义,应用于生产中的软件环境
- 11:20 黑盒测试:盒子是黑色的,你看不到里面的内容,内容即代码。白盒测试:盒子是白色(透明)的,你可以看到里面的内容,也就是代码
- 13:05 测试级别:从测试颗粒度上来说,从左到右,依次颗粒度增大。颗粒:可以理解为一个测试点对应的代码量,是一个整体,不可分割的。越往右走,测试人员越应该关于最终用户的使用
- 34:00 java中的 "for(类型 变量 : 类型的集合)",是用来遍历类型的集合的,是for(int i=0;i < 类型的集合.length;i++)的变体
- 38:50 javac -cp,-cp==-classpath, 让 java解析器 去查找用户类文件和注释处理程序的位置
- 1:20 java -cp .;junit-4.12.jar;hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorTest,org.junit.runner.JUnitCore就是我们说的测试运行器(Test Runner)
- 1:40 要非常清楚5个注解批注的运行时间(什么时候运行),运行次数,对函数的要求(public,void,static)
- 3:30 assertEquals,注意:是Equals,复数
- 5:30 代码必须抛出特定异常,如果抛出异常,我的测试就“成功”,否则,函数有问题,测试就是“失败”
- 6:15 这5个异常什么时候会出现,记好异常类型,对分析程序的错误所在和原因,非常有效
- 6:55 为什么现在要求JDK/JRE,真正的生产环境使用64位的?32位的内存空间限制太大(学过操作系统我们都知道,32位的寻址空间限制,导致32位jdk的内存使用量不能超过4G,真正用于当前Java项目的,就更少)
- 8:30 例如:游戏对战逻辑,就必须要对Timeout进行限制,否则,游戏的可玩性就无从谈起了
- 如果直接将jre文件夹放到eclipse.exe同级别目录,即使不配置Java的环境变量(JDK1.5以上,只需要JAVA_HOME和Path),Eclipse 也能正常运行。 所以,即使安装的是32位jdk,要一个64位jre,就可以运行最新版Eclipse。
- 12:05 Eclipse平台(对,它其实是一个平台),提供的这个选择view的方式,现在流行的IDE基本都有类似的功能
- 13:35 Ignore,设置以后,不是为了从此不用这个测试方法了,往往是“还没有完成”的意思
- 14:35 @Test注解,接受参数时,一般就2个:expected(异常类) 和timeout(毫秒)
- 15:50 代码出异常了,但是符合了测试用例的设计,所以“测试成功,测试通过”
- 16:30 Thead.sleep(),接收的是毫秒数,通过类的静态函数sleep()控制当前代码所在的进程“休眠”
- 有一个小问题,我这样写,对吗? @Test(excepted=ArithmeticException.class,timeout=200)
- 有人可能会说,怎么计算机的题,都是些“找不同”啊?!! 对,就是因为“细节”容易犯错误
- 比如:assertEquals,而不是Equal,same而不是some,越简单,越觉得不值一看,越容易忽略
- 老师 二维数组怎么打印来着 toString也是打印hashcode
- 二维数组,还是双重foreach或者for吧
- 没有方法吗
- 没有太能偷懒的办法,但是,Java中的二维数组,其实还是1维数组的概念,只不过,每一个元素是特殊的,
- 要不,Arrays.toString()方法的参数接受的也是个一维数组呢
- int [] intList = [4,3,2,1,2,3];
- Arrays.toString(intList);
- 结果就是: [4,3,2,1,2,3] ,所以二维数组打印,你起码要一个for
- 2:30 核心、逻辑、对象、文本、集合、数字(6大类的匹配器)
- 现在hamcrest表达式,在PHP,Ruby,Python等语言上也都适用
- 7:20 尽量使用hamcrest-all 的jar包
- 7:30 hamcrest表达式的规律是:assertThat(期望值,匹配器),我们这节课要探讨的就是《匹配器》的使用
- 11:20 Eclipse中,有“workspace”的概念,活用工作空间,对管理你本地的项目至关重要。
- 第一行的Matchers.*,防止我们每个匹配器都要重新import
- 15:30 如果不是用hamcre-all的jar包,而是使用hamcrest-core的jar包,很多匹配器将会报错。
- 18:20 选中某一个测试用例,可以只运行它自己,而不必当前类中所有的测试用例都执行一次。
- 21:45 anything(),见名知意,当前匹配器是个“老好人”,只要执行,就会匹配成功
- 22:15 is(equalTo(x))的简写,两者等价,用来“装饰”另一个匹配器,使其更有表现力(更好理解)
- 23:10 assertThat("fff", is(equalTo("fff"))); // 翻译成自然语言:我认为,“fff” is equal to "fff"。确实灵活了
- 24:15 allOf(), 对应逻辑与。所有匹配器为true,最终才是true
- 25:25 anyOf(),对应逻辑或。只要有一个匹配器是true,最终就是true
- 25:30 逻辑匹配器,是一个可以接受多个匹配器作为参数的匹配器
- 27:15 not(),是逻辑取反的函数 assertThat("fff",is( not(containsString("a")))); // 翻译成自然语言:我认为,“fff” is not contains string "a"
- 从这里也能看出来is()的作用,用来“装饰”语句更接近自然语言的习惯
- 28:25 equalTo(): 判定的是“值”相等,另外,这里是单词的单数,不是复数
- 28:56 hasToString(),判定测试值有toString()方法,另外,toString()的返回值跟我们的期望值一致
- 32:20 equalToIgnoringWhiteSpace 忽略前导和尾部空格
- 33:55 array()匹配器,匹配的规律是:“一一对应”
- 34:15 ,hasItem()匹配器,内部可以是匹配器
- 35:25 array()和hasItemInArray()匹配器的关系,类似于allOf()和anyOf()
- 36:30 ,容忍值的出现是有原因的,浮点数由于存储类型与整型不一样,所以小数点后面的数值会出现不精确的情况,所以,我们比对2个浮点值相等,是这样的:if( floatA - floatB < 0.000001) 0.000001,就是容忍值,比如:我们要求数值的精度是小数点后面2位,那么我们使用0.0001作为容忍值,就可以保证floatA 和floatB 的相等判断是正确的
- 实际的软件开发中,浮点数的使用远远大于整型
- 其实,eclipse的项目和NetBeans的项目,目录结构很明显
- NetBeans的,有nbproject文件夹
- 【语句覆盖率= 已经执行的语句÷语句总数】
- 3:00 代码覆盖类型包括:语句覆盖,函数覆盖,条件覆盖,循环覆盖
- 5:20 5行代码,前4行执行了10此,第五行一次没执行,那么覆盖率仍然是80%
- 各位注意一下,需要使用Jacoco的项目,项目路径中不允许出现中文,空格,特殊字符等
- 各位注意一下,需要使用Jacoco的项目,项目路径中不允许出现中文,空格,特殊字符等
- 各位注意一下,需要使用Jacoco的项目,项目路径中不允许出现中文,空格,特殊字符等
- 出现这个错误消息,说明jacoco安装了,但是执行的时候有问题,找不到相关需要处理的数据,找不到的原因大概是。
- 这是java早起的类库常犯的错误!!! 解压包自带中文 ,这个雷,早踩晚踩都得踩 ,带中文真不是故意加的坑你们的,但是,我之前真的是提前提醒了好几次/流泪
- 做Java开发,项目放中文路径就是个隐藏在最后的“彩蛋”,你不知道你的代码什么时候会爆发
- 另外,NetBeans,Eclipse,包括Idea(大部分java 的IDE),都会默认先检测自己程序所在目录是否有“jre”这个目录,如果有,则会优先使用此目录下的jre环境。所以当你将jre目录复制到Eclipse目录下之后,你的Eclipse就变成了“绿色版”
- 另外,Eclipse之所以提供一个叫“work-space"的设置,就是为了让开发人员平时将代码放到它里面,然后这种”中文路径“的问题,很多时候就自动避免了
- 另外,这个软件内部内多http请求,所以会被杀毒软件误杀
- 2:00 "桩模块":有就可以,我给你输入,你给我输出,保证我的代码能够按照规划的业务执行下去,哪怕你的模块里面只有一个return语句,但是,我的业务逻辑正常执行下去了
- 3:00 7个业务步骤,如果等到所有的都完成了再测试,后期代码变动带来的风险会非常大,所以,我们可以使用“桩模块“的方式,先略过一些业务,保证常规业务流程的逻辑是”按照我们预期的执行了“
- 6:00 "桩模块",不会增加测试代码和我们业务代码之间的耦合性
- “桩模块”的实现,需要“接口机制”的支持。我们依赖的类还没有实现,但是这个类实现自一个接口,那么我们先通过自己实现一个此接口的类,返回我们“要求的固定值”,来解除对此类的依赖
- 在你截图的代码中,如果【EasyMock.replay(emailChecker);】没有执行的话,会怎么样?为什么?
- 会报错,代码里如果一个接口多次调用,会无法对接口方法进行mock,EasyMock.replay()是将Mock的行为按照mock的步骤重发一遍,在单元测试运行的时候,就能够正确的执行
- 缺少了“注册”,那么我们的“设置的期望值”根本不会起作用(我们姑且对运行说参数错误的情况不提),也就是说,EasyMock根本没有模拟我们的“期望”
- 【boolean result = register.verify(name, email);】verify中的verifyEmail()是哪个实例的?我们在这个测试代码中并没有创建verifyEmail()所隶属的实例
- 没有replay但是可以得到结果是为什么
- 得到的不是测试结果,是测试用例代码运行完毕的内容,其实是:你的测试用例并没有执行(不对也不错)
- 测试结果应该是:什么都没有(通过) ,告诉你:我期望是A,结果是B(不通过)
- 已经分清楚:断言失败和程序失败是两码事儿 ,emailChecker示例是EasyMock创建的
- 下面的代码又用到了EasyMock的中间产物,所以,不满足EasyMock的所有步骤,测试不会正常执行(没有结果)
- 但是,我们其实没有创建EmailChecker的实例
- 当boolean result = register.verify(name, email);这句话执行的时候,EasyMock是根据我们EasyMock.expect()设置的期望值来返回结果的,并且在EasyMock.expect中,我们定义了是设置的verifyEmail()函数的传入参数。所以EasyMock会“模拟”输出,并不是真正的实例化了一个“实现了IEmailChecker”的对象
- 没有创建EmailChecker示例,是说没有用New的方式
- 建议大家:认真分析一下我们EasyMock和普通的桩模块测试代码的不同之处,好好理解一下EasyMock的工作原理
- 其实,EasyMock 使用了Java的反射机制,尤其是在expect()函数使用的时候
- EasyMock.verify(emailChecker); / / 不是参与的测试用例,而是来验证我们通过Mock创建出来的这个IEmailChecker接口对应的类的模拟实例,是否按照我们expect的条件执行了
- boolean result = register.verify(name, email); // 这句话因为前面有replay()和expect(),所以,result确实等于true,所以,assertTrue确实断言成功
- emailChecker是一个实例,是由EasyMock.createMock 创建的“实现了IEmailChecker接口的类的实例”
- 但是,这个实例隶属的类,我们不知道是哪个(这是EasyMock利用反射和下面的expect为我们构建出来的一个能返回true的代码段)
- 利用反射,EasyMock可以轻松知道我们要模拟的方法的传入参数个数和类型,以及返回值的类型,所以在expect执行后,EasyMock就根据传入参数的值,模拟了一个返回值的输出。
- 是的,虚拟类中,可能只有一个return true;因为我们的andReturn()方法要求返回true
- 我们可以这样假想:
- expect之后,有这样一段代码在我们的verifyEmail函数中:
- if( email=="[email protected]"){ return true;}
- verify()函数验证了expect的输入和andreturn之外的
- 我们是mock了一个IEmailChecker的实例,Registration中还得用到它呢
- 你删除了,怎么把这个实例传给Registration内部
- 对了,我们就是用这个构造函数把我们模拟的对象传进的呀
- 接口没有实例,实现了他的类才能创建实例
- 但是EasyMock可以为我们模拟出来一个实现了指定接口的类的实例(这个类我们姑且称为匿名类)
- 在我们EasyMock中,并没有使用a这样的类,只用到了接口IEmailChecker
- EJB: 商务软件的核心部分是它的业务逻辑。业务逻辑抽象了整个商务过程的流程,并使用计算机语言将他们实现。EJB 是为了"服务集群"和"企业级开发",将业务逻辑从客户端软件中抽取出来,封装在一个组件中。这个组件运行在一个独立的服务器上,客户端软件通过网络调用组件提供的服务以实现业务逻辑,而客户端软件的功能单纯到只负责发送调用请求和显示处理结果。
- 8:10 默认的glassfish的安装目录是:【C:\Program Files (x86)\glassfish-4.1.1\glassfish\lib\embedded】,Linux和Mac需要自己到自己解压的位置去找一下
- Derby:Apache Derby是一个完全用java编写的数据库,Derby是一个Open source的产品,基于Apache License 2.0分发。Apache Derby非常小巧,核心部分derby.jar只有2M,所以既可以做为单独的数据库服务器使用,也可以内嵌在应用程序中使用。
- JPA :JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 其一,简化现有Java EE和Java SE应用开发工作;其二,S整合ORM技术,实现统一化。
- Java还属于Sun的时候,Derby被开发了出来,作为Java自己的内置轻量级数据库,可是没想到让Sqlite给暗度陈仓了。不得不说,Android是一个很大的推手。
- 重点看一下在测试用例中,这种需要container的是如何实现“测试前准备”的,以及“上下文(context)”的概念
- Jenkins的功能: 自动获取代码,并编译。
- 测试人员或者产品发布人员,从Jenkins编译结果中下载即可。所以,jobs目录保存了当前自动构建项目的所有编译结果,(有可能也带着源代码)
- EasyMock需要expect和replay,Mockito需要when().thenReturn()
- A:只执行插入,如果主键已经存在了,插入会由于主键冲突失败
- B:先清空,在执行插入,这样主键永远不会冲突,但是,原来表中的数据就没有了
- createMock:创建常规模拟对象
- createNiceMock:可以创建随意的模拟对象(创建的不符合规范也不报错)
- createStrictMock:最严格的,创建的稍有不规范,mock失败
- 逗号分隔符:简称csv,Comma separator,value
- csv可以用excel打开,其实是excel兼容这种格式,csv实际是文本文件,除了csv,还有tsv:tab separator value
- DELETE,只删除数据集里面有的
- DELETE_ALL,数据集对应的表中的数据,都删除
- 文本相应:就是请求后,返回的所有文本(html等)
- 响应代码:200(成功),404(找不到),500(服务器内部错误),403(没有权限)
- 响应消息:success,not found, error, access deny URL:你请求的链接
- 比如:
int a=1,b=2;
if(a=b){
print("hello");
}- 在编程中,往往是:非0即为真,就因为这种错误,据说:当时的阿波罗航天飞机爆炸,跟这个有关系(程序员背锅) 这都是C的影子
- 不过,程序员确实干过很多高风险的事儿,比如前段时间:XX删库事件 rm -rf *
- 在信息安全等级比较高的公司,一般人没有rm权限
- 如果将来你们当老总,一定记得,不要相信你的员工会帮你考虑所有隐患