测试用例-单元测试

这篇具有很好参考价值的文章主要介绍了测试用例-单元测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

单元测试——编写手册

1.简述

本文主要针对如何使用Junit编写单元测试进行描述
文中的实例基于Junit 4

所谓单元测试,即是指针对程序中的一些单元进行测试的方法
这些单元在Junit中的最小单位为方法
借助单元测试,我们可以轻松地单独测试程序中的某一个逻辑片段而不需要在意程序的外部依赖和其它逻辑
接口测试 单元测试
只能以接口为维度进行测试 只需被测试的单元逻辑正常即可
工程必须编译通过并打包进行部署 可以不依赖外部,测试进度不再受制于外部条件
工程的外部依赖(数据库、调用的服务等)必须就绪 可以以方法为维度进行测试
难以测试复杂的逻辑分支,为测试数据需要调整各个数据源(数据库、缓存、消息队列) 可以根据单元的逻辑复杂程度编排测试用例数量,测试使用的数据可以自由调整

2.创建测试用例

2.1工程准备

  1. 确保工程的maven依赖中包含junit,版本至少为4.12,一般包含在spring-boot-starter-test中;

  2. 确保工程的目录中包含src/test/java和src/test/resource;

    *部分工程没有src/test的相关包,需要手动创建
    *src/test/java主要用于存放测试用例和测试相关的类
    *src/test/resoutces主要用于存放测试使用的配置和资源文件

2.2 编写测试启动类

许多工程在启动时需要加载许多配置类,与外部系统进行连接,非常复杂
为了使单元测试更加轻便,我们可以编写单元测试专用的启动类,屏蔽一些不相关的启动项
若你的工程启动和外部连接依赖本身就很简单,可以省略这一步,不写测试启动类则执行测试时默认使用	src/main/java下的启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
 
@ComponentScan(basePackages = { "需要扫描的包名" }, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = { 扫描的包中需要排除的类 }) })
@SpringBootApplication(exclude = { 需要排除的一些启动时自动配置类 })
public class TestApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

这个启动类中常用的配置如下

  1. @ComponentScan
    用于扫描指定的包,excludeFilters用于排除扫描的包中不需要的Bean
  2. @SpringBootApplication
    用于排除一起自动配置的启动类,防止诸如数据库、Mongo等启动类进行外部连接
    测试的启动类与工程的启动类类似,它通常防止在src/test/java下的项目根包中

其中“需要扫描的包名”和“扫描的包中需要排除的类”根据具体的工程决定,可按需将工程中的一些启动时配置类排除在外(Cache配置等),保证你测试的类以及它们的直接依赖被扫描到即可
“需要排除的一些启动时自动配置类”可参考如下对照表按需排除

作用 全类名
MongoDB自动配置 org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration
数据源自动配置 org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
Hibernate注解自动配置 org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

启动类的扫描配置决定了测试用例的范围以及启动速度
可以按需编写多个不同扫描范围的启动类以适配不同的测试需求

2.3 构建抽象测试类

根据启动类创建一个抽象测试类是个好方法,它能够让你在创建测试用例时通过选择继承的父类直接确定使用的测试启动配置。

import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
 
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = 启动类)
public abstract class BaseTest {
 
}

@SpringBootTest
用于指定测试的一些主要参数,主要是classes,用于指定关联的启动类,这样继承自这个类的所有子类都会使用相同的启动类

2.4 使用测试专用的配置

就像在工程部署时我们可以指定不同环境的配置文件一样;
执行测试时我们也可以使用不同的配置文件;
使用自定义测试启动类的情况下将配置文件放置在src/test/resource下则测试类默认会使用该包下的配置和资源文件;
由于测试启动类中通常会排除许多与测试目标无关的类,所以测试专用的配置文件可以更加轻量化,哪些被排除的类所引用的配置都可以省略;

2.5 新建Test类

针对一个被测类创建一个测试类
测试类通常以被测类的名字+Test进行命名,并放置在与src/test/java下与被测类同包名的包中
  1. 根据被测类创建测试类
  2. 配置测试类的参数,通常这些参数会按照约定给出一些默认值;
  3. 选择要测试的方法,注意:junit测试只能对非private方法进行测试DemoServiceTest,测试用例在src/test/java下的被测类同名包中;此时可以选择继承的父类,根据测试需要进行继承
  4. 生成测试类,得到一个单元测试类的骨架,包含了选择的方法的测试用例

编写用例

3.1 了解Mock测试

测试用例-单元测试
一个Bean通常会形成一个依赖树,这种发散的依赖结构导致我们在测试一个类的逻辑时其实是连同它所依赖的逻辑一同进行测试

此时使用Mock测试就可以解决依赖过多,逻辑复杂的问题

Mock以为模拟、虚拟,就是将原有的逻辑进行模拟,使用规划的Mock方案逻辑进行替代

在Mock测试中,我们通常对测试对象的所有直接依赖进行Mock,被Mock的直接依赖将变成只有方法签名的空壳

被调用时它们不会再调用间接依赖,也不会执行原有的逻辑,只会根据Mock方案进行返回

这样在测试测试对象时我们就不在需要关心它负载的间接依赖关系和所有依赖的内部逻辑了,只需要专注于当前测试对象的逻辑即可

3.2 完全Mock依赖

这种测试仅测试测试对象内部的逻辑,屏蔽所有测试对象的依赖
适用于测试内部逻辑较为复杂的对象,或依赖较为复杂的对象
样例:
测试用例-单元测试
注意

  1. @MockBean标记的依赖的方法默认变为空方法且返回值为null,一定要配合mock方案才能执行逻辑和获取返回值(参照FAQ-@MockBean与@SpyBean)
  2. mock方案的编写参照FAQ-mock方案
  3. 需要调用@MockBean标记的类中无返回值的方法时可以不编写mock方案,但一定要校验调用是否执行(参照FAQ-验证调用是否执行)

3.3 完全真实依赖

这种类型的测试同时测试测试对象及全部其依赖的逻辑,针对实际调用流程进行测试
适用于测试一个完整的流程以及测试调用链路正确性

样例
测试用例-单元测试
注意

  1. 这种测试方式与Mock毫无关系,为常规的方法逻辑调用
  2. 测试的结果与输入的数据、持久化的数据、程序逻辑直接相关,因此需要事先准备好配套得入参、数据库脚本/Redis缓存并熟悉程序的逻辑,以此推导出正确的处理结果

3.4 Mock与真实依赖相结合

这种类型的测试同时测试测试对象及其部分依赖的逻辑,屏蔽部分较为复杂的依赖同时对实际调用流程进行测试
适用于测试一个部分依赖较为复杂的流程以及测试调用链路正确性

样例:
测试用例-单元测试
注意

  1. @SpyBean标记的依赖的方法默认为真实逻辑,若配合mock方案则在入参与mock方案一致时根据mock方案的设置进行返回(参照FAQ-@MockBean与@SpyBean)
  2. mock方案的编写参照FAQ-mock方案
  3. 需要调用@SpyBean标记的类的方法的真实逻辑时可以不编写mock方案
  4. 测试的结果与输入的数据、持久化的数据、程序逻辑、mock方案均相关,因此需要事先准备好配套得入参、数据库脚本/Redis缓存并熟悉程序的逻辑和mock方案的逻辑,以此推导出正确的处理结果
  5. 虽然@SpyBean标记的类在没有设置mock方案的情况下原则上与原类的逻辑一致,但由于底层实现原理的种种限制,它与原生的类在某些情况下不能完全一致;若想直接测试完全真实依赖的场景,请参照完全使用真实依赖的测试章节的描述

3.5 混合测试

对一个测试对象中的不同方法采取不同的测试策略
对同一个测试对象的不同方法根据需求采取“完全Mock”或“完全真实”或“Mock与真实结合”的方式;没有对同一个测试	对象编写多个不同类型测试用例的需求

注意

  1. 此种测试是其他3种的复合形式,单个用例内的书写参照相应章节的描述
  2. 此种测试的测试对象的依赖需要使用@SpyBean的方式进行标记,否则难以执行真实逻辑(参照FAQ-@MockBean与@SpyBean)

4. FAQ

4.1 @MockBean与@SpyBean

在进行mock测试或混合测试时可以看到这2中不同的设定测试对象直接依赖的注解
/ 相同 不同
@MockBean 提供mock测试能力mock方案的作用域都在一个@Test内 默认将标记该注解的类及其依赖的方法全部掏空,直接调用将没有任何执行逻辑并返回null(如果有返回值)
@SpyBean 提供mock测试能力mock方案的作用域都在一个@Test内 默认将标记该注解的类以及依赖的方法保持原样,直接调用将按照方法原本的逻辑执行并返回;可以按照混合测试的需求灵活决定是否mock
/ 使用场景
@MockBean 适用于标记的依赖需要被完全mock的场景,不配合mock方案使用易引发空指针异常
@SpyBean 适用于标记的依赖只有部分逻辑需要mock的场景,不配合mock方案则执行原方法,配合mock方案则执行mock方案

4.2 mock方案

在进行mock测试时需要提前针对被mock的逻辑进行规划
参照如下写法:

Mockito.doReturn(mockData).when(demoService).function(Matchers.eq(arg1), Matchers.eq(arg2));
Mockito.doNothing().when(demoService).function(Matchers.eq(arg1), Matchers.eq(arg2));
Mockito.doThrow(exception).when(demoService).function((Matchers.eq(arg1), Matchers.eq(arg2));
关键词 解释
doReturn(mockData) 模拟方法正常返回数据
doNothing() 模拟方法未执行(可用于没有返回值的方法)
doThrow(exception) 模拟方法执行时抛出异常
demoService 被@MockBean或@SpyBean标记的测试对象的直接依赖
function、arg1、arg2 直接依赖的方法名及其参数
Matchers.eq() org.mockito.Matchers提供的一些更灵活的mock调用时参数验证方法;验证通过时方法返回模拟的返回数据,验证不通过时方法按照@MockBean或@SpyBean的默认策略执行

4.3 同名方法调用多次

同名方法设置多个mock方案时,不同入参预期的方案都会保留,相同入参预期的方案以最后一个为准
例,设置了如下mock方案:

@MockBean
private DemoService demoService;
 
@Test
public void testFunction() {
    // 省略其他步骤,此处只展示mock方案设置
    // 方案1
    Mockito.doReturn(demoDataA).when(demoService).callFun(eq("alpha"));
    // 方案2
    Mockito.doReturn(demoDataB).when(demoService).callFun(eq("beta"));
    // 方案3
    Mockito.doCallRealMethod().when(demoService).callFun(eq("beta"));
}

方案1,3会生效,方案2会被方案3覆盖而失效
调用demoService.callFun(String)方法时:
若入参为"alpha",则返回demoDataA;
若入参为"beta",则执行该方法的真实逻辑并返回;
若入参为其他,则执行空方法并返回null(@MockBean的默认方案);
在上述场景的基础上,若被测方法中存在同一方法调用多次且入参相同,但根据执行顺序返回值不同,则参照如下写法(使用链式调用依序排布多个方案):

@MockBean
private DemoService demoService;
 
@Test
public void testFunction() {
    // 省略其他步骤,此处只展示mock方案设置
    // 方案1
    Mockito.doReturn(demoDataA).when(demoService).callFun(eq("alpha"));
    // 方案2(包含多次调用的方案)
    Mockito.doReturn(demoDataB).doCallRealMethod().when(demoService).callFun(eq("beta"));
}

调用demoService.callFun(String)方法时:

若入参为"alpha",则返回demoDataA;
若入参为"beta"且是该入参的第1次调用,则返回demoDataB;
若入参为"beta"且是该入参的第2次调用,执行该方法的真实逻辑并返回;
若入参为"beta"且是该入参的第3次及以上调用,执行方案链中最后一个方案(例子中为调用真实逻辑);
若入参为其他,则执行空方法并返回null(@MockBean的默认方案)

4.4 验证调用是否执行

在mock测试中需要验证mock方案标记的方法是否按照预期的入参执行过,若缺少这一步可能导致测试用例出现未预期的成功
例,一个用例按如下步骤执行:

  1. 测试的依赖使用@SpyBean标注
  2. 执行到mock方案对应的方法,入参与mock方案预期不一致
  3. 方法按照真实逻辑执行
  4. 方法的返回值恰巧与预期一致
  5. 测试成功

上述例子的用例可能会在某次数据库数据变动,外部链接中断的场景下执行失败
增加验证调用是否执行的步骤可以解决该问题
写法如下:

Mockito.verify(demoService).function(Matchers.eq(arg1), Matchers.eq(arg2));

与mock方案中的写法非常相似
当同名方法调用多次且入参一致时采用如下写法:文章来源地址https://www.toymoban.com/news/detail-407042.html

Mockito.verify(demoService, new Times(2)).function(Matchers.eq(arg1), Matchers.eq(arg2));

到了这里,关于测试用例-单元测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Angular入门:简述单元测试排错

    学习Angular的时候,总感觉特别的复杂、高级,以至于产生畏惧心理,这种心理尤其体现在 单元测试 上。 今天被醍醐灌顶之后,感觉单元测试的报错信息也不是那么难看懂了。 (文章的后半段是记录我自己的一次单元测试的过程,为了不耽误读者时间,我把结论写在第一小节

    2024年02月19日
    浏览(37)
  • 软件测试-测试的概念,单元测试的详细介绍,如何设计测试用例

    作为测试工程师,你就必须掌握设计开发测试基础架构的关键技术。第三,随着自动化测试的规模化,测试数据准备的各种问题被逐渐暴露并不断放大,成为影响自动化测试效率以及稳定性的“拦路虎”。早期的传统测试数据准备方法,无论是从测试数据准备的时间成本,还

    2024年04月14日
    浏览(67)
  • 测试用例-单元测试

    本文主要针对如何使用Junit编写单元测试进行描述 文中的实例基于Junit 4 接口测试 单元测试 只能以接口为维度进行测试 只需被测试的单元逻辑正常即可 工程必须编译通过并打包进行部署 可以不依赖外部,测试进度不再受制于外部条件 工程的外部依赖(数据库、调用的服务

    2023年04月09日
    浏览(31)
  • 如何编写测试用例?

    带着问题学习是最高效的学习方法。 因此,在介绍如何编写测试用例之前,先看一个软件系统登录功能的测试(如下截图所示): 要做这个登录页面的测试用例,你会从哪些方面思考进行测试呢? 看似简单的页面功能能够设计多少条测试用例完成较全面的测试呢?10条以内

    2024年01月25日
    浏览(49)
  • 如何编写测试用例?流程及5大编写步骤

    编写测试用例的5个步骤: 1.选择测试工具 ; 2.确定测试场景 ; 3.编写测试用例 ; 4.确认测试用例 ; 5.组织测试用例 。但在编写测试用例之前,测试人员需要充分了解软件的需求和规格,以确保测试用例能够覆盖所有的功能和场景。 测试用例是一种用于验证软件或系统功能

    2024年02月04日
    浏览(79)
  • 【测试效率提升技巧】xmind测试用例转换为excel工具使用手册

    1.在命令行执行pip install xmind2testcase -U 2.到python中xmind2testcase的安装路径(我的路径是D:pythonLibsite-packagesxmind2testcase)下新建一个文件夹,命名为web 3.在命令行cd到刚刚创建的web文件夹,执行pip freeze requirements.txt 4.命令行执行pip install -r requirements.txt -U PS:请尽量使用xMind8 Up

    2024年02月12日
    浏览(44)
  • 正交实验法编写测试用例

    一、常见设计测试用例的方法: 语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖 语句覆盖:被测程序的每一个语句至少执行一次 判定覆盖:每个 判定 的 所有可能 结果 至少出现一次 条件覆盖:每个 条件 的所有可能 结果 至少出现一次 判定/条件

    2024年02月11日
    浏览(54)
  • Selenium 测试用例编写

    编写Selenium测试用例就是模拟用户在浏览器上的一系列操作,通过脚本来完成自动化测试。 编写测试用例的优势: 开源,免费。 支持多种浏览器 IE,Firefox,Chrome,Safari。 支持多平台 Windows,Linux,Mac。 支持多语言 Python,Java,C#。 对 Web 支持良好。 简单,灵活。 支持分布式

    2024年02月12日
    浏览(34)
  • 测试用例编写规范参考

    规范合理,可执行性。 一定要保证高可读性。 同级别、同等级功能点。 产品线下的业务模块。 子功能点。 主干用例库中的产品、功能点已废除的需要删除。 单用例 : 一个功能的正常流程。 同一功能,不同入口。 多用例 : 同一功能,多个异常流程。 同一功能,不同数据

    2024年02月10日
    浏览(37)
  • VectorCAST单元测试手动配置测试用例

    一、单元测试 等待环境创建完成后,就可以开始单元测试。 二、生成测试用例 在 VectorCAST 中,一共有两种方法来生成测试用例,一种是手动生成测试用例,另外一种是自动 生成测试用例。 三、手动生成测试用例         在 VectorCAST 中,手动生成测试用例,需要根据函数

    2024年02月12日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包