
代码测试总结
基本概念H2
单元测试H3
一些单元测试中设计的基本概念
- Stub 指的是以可控的方式对对象方法进行模拟,使其按照预期的行为返回结果或抛出异常等的过程。
- Mock Object 整个对象都是模拟对象,所有方法在模拟之前进行调用都是空方法。
- Spy Object 对真实对象的部分方法进行模拟,除了模拟的方法外调用的都是真实的方法。
单元测试的主体对象是方法,目的是测试目标方法的执行是否符合预期的行为,包括执行路径、返回值等。实施单元测试的主要目标是应用的POJOs。测试这些对象应该通过new来进行初始化,而不是通过从容器中获取的对象。目标方法中调用的过程中会调用其他的对象方法,可能基于下面的这些原因
- 真实对象的行为是不确定的(例如,当前的时间或当前的温度);
- 真实对象很难搭建起来;
- 真实对象的行为很难触发(例如,网络错误);
- 真实对象速度很慢(例如,一个完整的数据库,在测试之前可能需要初始化);
- 真实的对象是用户界面,或包括用户界面在内;
- 真实的对象使用了回调机制;
- 真实对象可能还不存在;
- 真实对象可能包含不能用作测试(而不是为实际工作)的信息和方法。
不能够或者不应该使用真实的对象方法。使用Mock对象,可以避免其他方法执行结果对目标方法执行的干扰,同时能够更好的控制方法的执行路径。
实施单元测试的好处不仅仅在于它能保证代码的正确性,更大的好处在于它的高效,因为它是通过new初始化的,调用的对象也可以进行mock,并不依赖于难以控制的外部环境。另外的好处是可以间接地提高代码的品质要求,如果你想实施单元测试,那么你得要求你的类尽可能的是一个POJO,代码应该应有较好的分层结构以及松散的耦合,一段品质很差的代码要实施单元测试是非常苦难的。
如何进行MockH4
下面是基本的mock准则
- 不要什么都mock
- 不要mock不是你的类
- 不要mock值对象
针对大多数的mock框架,使用mock对象的步骤大致是一致的
- 创建mock对象
- 录制需要mock的方法行为
- 调用mock对象
- 验证
下面是Mocktio的示例代码
bash
// you can mock concrete classes, not only interfacesLinkedList mockedList = mock(LinkedList.class);// stubbing appears before the actual executionwhen(mockedList.get(0)).thenReturn("first");// the following prints "first"System.out.println(mockedList.get(0));// the following prints "null" because get(999) was not stubbedSystem.out.println(mockedList.get(999));// virify get(0) is calledverify(mockedList.get).get(0);
集成测试H3
集成测试主要针对是测试多个组件组合在一起工作的情况。 例如Repository接口和Spring Data JPA集成的情况下,生成的查询接口测试;Web框架和Controller集成的情况下,请求参数的绑定、转换、验证是否正常;和消息中间件集成时,消息的收发是否正常等等。
功能测试H3
功能测试有时候也叫E2E测试,功能测试以系统的功能点为测试对象。以Web应用为例,功能测试的主要应该是测试页面的功能是否正常,例如测试
- 请求是否成功
- 重定向是否正确
- 用户是否成功授权
- 页面的元素是否正常显示
- 页面的表单的验证是否正确,提交后的跳转是否正确
功能测试最常用的工具Selenium。当然有些框架也提供应用内的功能测试,例如Rails的Functional Test,但是这些测试不属于E2E测试的范畴,因为他们是基于容器内的测试,而不是完全独立的端到端的测试。
测试逻辑
bash
CreateMessagePage page = CreateMessagePage.to(driver);ViewMessagePage viewMessagePage =page.createMessage(ViewMessagePage.class, expectedSummary, expectedText);assertThat(viewMessagePage.getMessage()).isEqualTo(expectedMessage);assertThat(viewMessagePage.getSuccess()).isEqualTo("Successfully created a new message");
测试方法H2
Behavior-driven development(BDD)H3
行为驱动开发是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。 BDD是一种开发方式,但是它和测试紧密相关。BDD用它的DSL来描述系统的功能的,测试用例则则相当于对功能描述一个实现。
CucumberH4
Cucumber是一个BDD的框架,它支持各种语言的实现。
业务描述H5
Cucumber使用Gherkin语言来作为DSL来对业务规则进行描述,下面是一个Gherkin的文档
bash
Feature: Refund itemScenario: Jeff returns a faulty microwaveGiven Jeff has bought a microwave for $100And he has a receiptWhen he returns the microwaveThen Jeff should be refunded $100
一个Scenario指的是一个业务规则的演示、描述。其中包括Give、And、When、Then等多个Step。
上面的文档就是非技术人员或商业参与者需要做的,使用DSL语言对系统功能进行描述。
步骤实现H5
开发人员则需要对上面的文档中的描述进行实现,调用实际的功能代码,以达到测试代码的目的。
例如,针对下面的Step
bash
Scenario: Some cukesGiven I have 48 cukes in my belly
进行实现
bash
@Given("I have (\\d+) cukes in my belly")public void I_have_cukes_in_my_bellt(int cukes) {System.out.format("Cukes: %n\n", cukes)}
实现方法是应该调用实际的业务代码,对于Given来说,应该是类似setUp来初始化测试上下文环境的。
测试框架H2
下面主要介绍下各个平台中较为广泛的使用的测试框架
Test RunnerH3
Test Runner是用来启动测试,调用测试代码,反馈测试结果的。它本身可能作为一个测试框架还包括了断言、Mock等其他额外的功能
- Karama 它作为JS的Test Runner,仅负责测试的运行。它是一个Node.js的模块,能够在本地启动浏览器执行测试用例,并将测试结果输出到本地控制台。
- Junit Java平台的测试框架,它是一个完整的测试框架,除了负责运行测试用例,它还包括测试方法定义,断言的书写等功能。
- XCTest 从Xcode5,使用XCtest作为OS X和iOS平台的完整测试框架。
BDDH3
即便开发团队不使用完整的BDD框架进行开发,使用BDD风格的测试用例描述方式,仍然有诸多的有点,测试用例具有良好的可读性。
下面是一些BDD测试框架,其中一部分虽然是测试框架,但也创建拥有功能描述文档的功能
- Jasmine 基于JS的完整BDD测试框架,包括断言、mock的功能。
- Spock 基于Groovy的BDD测试框架,有用自己特有的断言方式,也支持使用groovy-test的断言。
- Specta 基于Object-C和Cocoa的BDD测试框架,它不提供断言、mock的功能。
- Kiwi iOS平台的完整BDD测试框架,包括了断言、mock的功能。
Mock库H3
除了针对对象方法的mock库,还有一些实现了类似mock功能的库。
- [OHHTTPStubs] iOS平台的HTTP请求的Stub库。它可以Stub所有通过NSURLConnection接口进行的请求,模拟数据的返回,模拟网速慢的情况的请求等。 除了可以用于更高效的测试外,还可以用于开发阶段,API等尚未完成时的接口模拟等。
断言&匹配库H3
匹配库本身并不是测试必要的一部分,但是有了匹配库可以让断言的书写更为简洁和高效
评论
新的评论
上一篇
CICD Renewal
持续集成 依然使用Gitlab CI作为CI工具,一些重要的特性 通过service 使用dind 通过 dotenv 传递任务间的环境变量 强大的rules设置:仅PR时触发CI 阶段和任务 build build gradle/npm build test code_a…
下一篇
用Spring Test进行页面的功能测试
Spring Test Spring Test框架提供的MockMvc可用于实现Controller的集成测试。 例如 如果想更新一步,对页面的功能功能测试,也是可以的 但是这样的测试代码的有不少缺点,代码重复性较高,可维护性较差,页面稍微变更,现有的代码的xpath也不得不修…
