如何进行单元测试

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

  1. 前言

单元测试是指对软件中最小可测单元进行检查和验证;c语言中单元指一个函数,java中指一个类。图形化软件中可以指一个窗口或者一个菜单。总的来说,单元就是认为规定最小的被测试模块。

1.1单元测试对我们开发程序有什么好处

首先是一个前端单元测试的根本性原由:JavaScript 是动态语言,缺少类型检查,编译期间无法定位到错误; JavaScript 宿主的兼容性问题。比如 DOM 操作在不同浏览器上的表现。

正确性:测试可以验证代码的正确性,在上线前做到心里有底。

自动化:当然手工也可以测试,通过console可以打印出内部信息,但是这是一次性的事情,下次测试还需要从头来过,效率不能得到保证。通过编写测试用例,可以做到一次编写,多次运行。

解释性:测试用例用于测试接口、模块的重要性,那么在测试用例中就会涉及如何使用这些API。其他开发人员如果要使用这些API,那阅读测试用例是一种很好地途径,有时比文档说明更清晰。

驱动开发,指导设计:代码被测试的前提是代码本身的可测试性,那么要保证代码的可测试性,就需要在开发中注意API的设计,TDD将测试前移就是起到这么一个作用。

保证重构:互联网行业产品迭代速度很快,迭代后必然存在代码重构的过程,那怎么才能保证重构后代码的质量呢?有测试用例做后盾,就可以大胆的进行重构。

  1. 规范

2.1 单元测试主体

大多数单元测试包括四个主体:

  • 测试套件describe、

  • 测试用例it、

  • 判定条件expect、

  • 断言结果toEqual。

2.2 单元测试用例的原则

  • 测试代码时,只考虑测试,不考虑内部实现;

  • 数据尽量模拟现实,越靠近现实越好,

  • 充分考虑数据的边界条件下·

  • 对重点、复杂、核心代码、重点测试

  • 利用AOP(面向切面编程),减少测试代码,避免无用功能

  • 测试、功能开发相结合,有利于设计和代码重构

  1. 常用框架

3.1 Spock

Spock主要特点如下:

  • 让测试代码更规范,内置多种标签来规范单元测试代码的语义,测试代码结构清晰,更具可读性,降低后期维护难度。

  • 提供多种标签,比如:givenwhenthenexpectwherewiththrown……帮助我们应对复杂的测试场景。

  • 使用Groovy这种动态语言来编写测试代码,可以让我们编写的测试代码更简洁,适合敏捷开发,提高编写单元测试代码的效率。

  • 遵从BDD(行为驱动开发)模式,有助于提升代码的质量。

  • IDE兼容性好,自带Mock功能。

3.1.1 为什么使用Spock? Spock和JUnit、jMock、Mockito的区别在哪里?

总的来说,JUnit、jMock、Mockito都是相对独立的工具,只是针对不同的业务场景提供特定的解决方案。其中JUnit单纯用于测试,并不提供Mock功能。

我们的服务大部分是分布式微服务架构。服务与服务之间通常都是通过接口的方式进行交互。即使在同一个服务内也会分为多个模块,业务功能需要依赖下游接口的返回数据,才能继续后面的处理流程。这里的下游不限于接口,还包括中间件数据存储比如Squirrel、DB、MCC配置中心等等,所以如果想要测试自己的代码逻辑,就必须把这些依赖项Mock掉。因为如果下游接口不稳定可能会影响我们代码的测试结果,让下游接口返回指定的结果集(事先准备好的数据),这样才能验证我们的代码是否正确,是否符合逻辑结果的预期。

尽管jMock、Mockito提供了Mock功能,可以把接口等依赖屏蔽掉,但不能对静态方法Mock。虽然PowerMock、jMockit能够提供静态方法的Mock,但它们之间也需要配合(JUnit + Mockito PowerMock)使用,并且语法上比较繁琐。工具多了就会导致不同的人写出的单元测试代码“五花八门”,风格相差较大。

Spock通过提供规范性的描述,定义多种标签(givenwhenthenwhere等),去描述代码“应该做什么”,“输入条件是什么”,“输出是否符合预期”,从语义层面规范了代码的编写。

Spock自带Mock功能,使用简单方便(也支持扩展其他Mock框架,比如PowerMock),再加上Groovy动态语言的强大语法,能写出简洁高效的测试代码,同时能方便直观地验证业务代码的行为流转,增强工程师对代码执行逻辑的可控性。

3.1.2使用Spock解决单元测试开发中的痛点

如果在(if/else)分支很多的复杂场景下,编写单元测试代码的成本会变得非常高,正常的业务代码可能只有几十行,但为了测试这个功能覆盖大部分的分支场景,编写的测试代码可能远不止几十行。

之前有遇到过某个功能上线很久一直都很正常,没有出现过问题,但后来有个调用请求的数据不一样,走到了代码中一个不常用的逻辑分支时,出现了Bug。当时写这段代码的同学也认为只有很小几率才能走到这个分支,尽管当时写了单元测试,但因为时间比较紧张,分支又多,就漏掉了这个分支的测试。

尽管使用JUnit的@Parametered参数化注解或者DataProvider方式可以解决多数据分支问题,但不够直观,而且如果其中某一次分支测试Case出错了,它的报错信息也不够详尽。

这就需要一种编写测试用例高效、可读性强、占用工时少、维护成本低的测试框架。首先不能让业务人员排斥编写单元测试,更不能让工程师觉得写单元测试是在浪费时间。而且使用JUnit做测试工作量不算小。据初步统计,采用JUnit的话,它的测试代码行和业务代码行能到3:1。如果采用Spock作为测试框架的话,它的比例可缩减到1:1,能够大大提高编写测试用例的效率。

3.2 Mockito

3.2.1什么是 Mockito

Mockito 是一个强大的用于 Java 开发的模拟测试框架, 通过 Mockito 我们可以创建和配置 Mock 对象, 进而简化有外部依赖的类的测试.

使用 Mockito 的大致流程如下:

  • 创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中.

  • 执行测试代码.

  • 校验测试代码是否执行正确

3.2.2为什么使用 Mockito

假设我们正在编写一个银行的服务 BankService, 这个服务的依赖关系如下:

单元测试方法,java基础,单元测试,java,junit,Powered by 金山文档

当我们需要测试 BankService 服务时, 该真么办呢?

一种方法是构建真实的 BankDao, DB, AccountService 和 AuthService 实例, 然后注入到 BankService 中.

不用我说, 读者们也肯定明白, 这是一种既笨重又繁琐的方法, 完全不符合单元测试的精神. 那么还有一种更加优雅的方法吗?

自然是有的, 那就是我们今天的主角 Mock Object. 下面来看一下使用 Mock 对象后的框架图:

单元测试方法,java基础,单元测试,java,junit,Powered by 金山文档

我们看到, BankDao, AccountService 和 AuthService 都被我们使用了虚拟的对象(Mock 对象) 来替换了, 因此我们就可以对 BankService 进行测试, 而不需要关注它的复杂的依赖了.

3.3 JUnit5

3.3.1 JUnit 5架构体系

作为最新版本的JUnit框架,JUnit 5相比之前版本的JUnit框架有了较大的突破,添加了许多新特性。

之前的JUnit 框架所有的功能都被打包在一个构件(artifact)中。它被提供给开发者、IDE、构建工具、其他测试框架、其他扩展等使用,不同的使用者,依赖的都是一个同样的jar包。

而JUnit 5 最重要的一大优化就是其架构体系,它由三个不同子项目的几个不同模块组成。

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit Platform 其主要作用是在 JVM 上启动测试框架。它定义了一个抽象的 TestEngine API 来定义运行在平台上的测试框架,同时还支持通过命令行、Gradle 和 Maven 来运行平台。通过 JUnit Platform,其他的自动化测试引擎或开发人员自己定制的引擎都可以接入 Junit 实现对接和执行

JUnit Jupiter 包含了 JUnit 5 最新的编程模型和扩展机制; Jupiter 本身也是一个基于 Junit Platform 的引擎实现。

JUnit Vintage 兼容JUnit3,JUnit4 版本的测试引擎

再来看下JUnit 5的架构图

单元测试方法,java基础,单元测试,java,junit,Powered by 金山文档

我们来进一步看看各个子项目的作用。

第一层 : 开发人员(这里只进行业务开发撰写单元测试) 使用junit-jupiter-api等测试框架api编写单元测试

第二层 : 测试引擎,JUnit 或其他测试框架实现引擎API的框架,jupiter-engine和 vintage-engine分别是junit 4和junit 5 对测试引擎API的实现,其他的测试框架也可以通过实现引擎API从而接入JUnit 平台

第三层: 平台引擎 junit-platform-engine 是上一层各种引擎实现的抽象,即引擎的接口标准。

第四层: 启动器 通过ServiceLoader发现测试引擎的实现并安排其执行。 它为IDE和构建工具提供了API,因此IDE可以与测试执行交互,例如,通过启动单个测试并显示其结果。

3.3.2 JUnit 5的新特性

  • 包可见性

在JUnit 4里我们的测试方法必须定义为public的访问级别,如果没有定义成public,虽然编译的时候不会提示异常,但是在运行时会提示 “java.lang.Exception: Method testIsBlank() should be public” 如下错误信息。

而在JUnit 5里,我们不再需要将测试类与测试方法定义为public了,默认的包可见的访问级别就可以了。

  • 常用注解

对于在JUnit 4中的常用注解,你都可以在JUnit 5中找到对应的注解,关系如下:

JUnit 5JUnit 4说明

@Test@Test指明被注解的方法是一个测试方法,注意JUnit 5的@Test在jupiter-api里

@BeforeAll@BeforeClass被注解的静态方法会在当前类的所有@Test方法执行前执行一次

@BeforeEach@Before被注解的方法会在当前类的每个@Test方法执行前执行一次

@AfterAll@AfterClass被注解的静态方法会在当前类的所有@Test方法执行后执行一次

@AfterEach@After被注解的方法会在当前类的每个@Test方法执行后执行一次

@Disabled@Ignore被注解的方法不会被执行,但是在测试报告里会记录为已执行

  • 测试命名

写测试用例的时候,为了更好的可读性,我们往往会给测试方法定义一个有意义的名字,eg.testXXXWhenXXXThenReturnXXX。JUnit 5还提供了一个@DisplayName 注解,方便我们为每个测试用例添加更具体的名字,更容易表述用例所要测试的内容(可以是字符串,特殊符号,甚至是表情符号)。

  • 断言

junit 框架中最常用的断言就是检查一个对象或者属性是否为null.或者判断两个属性是否一致。JUnit 4和JUnit 5中的断言方法都可以接受字符串作为一个可选参数,如果断言失败,则会在控制台输出对应的描述信息。JUnit 5中还可以使用 lambda 表达式 来构建这个描述信息。

注意一下,在JUnit 4和JUnit 5中描述信息的参数位置是不一样的。

  • tag标记

JUnit 5新增了@Tag注解,可以为测试类或方法添加标签,并在执行时快速地根据标签来针对性地运行测试。

  • 扩展机制

在JUnit 5出来之前,我们如果想对JUnit 4 的核心功能进行扩展,往往都会使用自定义Runner 和 @Rule。

自定义Runner 通常是 BlockJUnit4ClassRunner 的子类,用于实现 JUnit 中没有直接提供的某种功能。 eg.spring-test框架的SpringJUnit4ClassRunner, 和mock框架的MockitoJUnitRunner

局限性:

必须在测试类级别上使用 @RunWith 注解来声明 Runner 。

@RunWith仅接受一个参数: Runner 的实现类。因为每个测试类最多只能拥有一个 Runner ,所以每个测试类最多也只能拥有一个扩展点。(在PowerMock中引入了@PowerMockRunnerDelegate,可以同时使用两个Runner)

为了解决 Runner 的限制,JUnit 4.7 引入了 @Rule 。一个测试类可声明多个 @Rule ,这些规则可在类级别和测试方法级别上运行,但是它只能在测试运行之前或之后执行指定操作。如果我们想在此之外的时间点进行扩展,@Rule也无法满足我们的要求。

JUnit 5扩展机制的核心准则:

Prefer extension points over features

基于这一准则,JUnit 5 中定义了许多扩展点,每个扩展点都对应一个接口。我们可以定义自己的扩展可以实现其中的某些接口,然后通过 @ExtendWith 注解注册给 JUnit,后者会在特定的时间点调用注册的接口实现。

参考:

Spock单元测试框架介绍以及在美团优选的实践

学习单元测试 Mockito

Mockito详细教程

关于JUnit5 你必须知道的(一)

关于JUnit5 你必须知道的(二)

关于JUnit5 你必须知道的(三) 文章来源地址https://www.toymoban.com/news/detail-736548.html

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

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

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

相关文章

  • Java语言基础(4)IDEA程序debug断点调试与单元测试junit(图文简单超详细教程,一文搞定debug断点调试和junit单元测试)

    在代码中,找一个位置,点击 前面出现红色点:这个叫 断点 右击鼠标,选择Debug运行 下图:鼠标悬停上面,会提示如下 1、Step Over(F8):点击这个按钮,或者按住F8键,可以往后面执行 2、Step Into(F7):可以进入方法内部,如果当前执行到方法调用,就可以进入方法内部 3、Fo

    2024年02月20日
    浏览(47)
  • 软件测试--应用JUnit进行单元测试

    JUnit是一个开源的Java编程语言的单元测试框架,最初由 Erich Gamma 和 Kent Beck 编写。Junit测试是一种白盒测试工具。JUnit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。具有JUnit经验对于应用“测试驱动开发(TDD)”的程序开发模型是非常重要的。 JUnit本质上是一套框

    2023年04月12日
    浏览(42)
  • 使用Junit进行单元测试的简单例子

    首先新建一个工程,选择合适的路径和JDK版本,其它默认就行。 把Main.java内容改为如下。    后面就是对add方法增加单元测试 在project窗口中右击项目,在菜单中选择:New - Directory 在弹出的提示框中输入目录名:test 。 然后右击 project窗口中 test 目录,在弹出菜单中选择:

    2024年02月09日
    浏览(58)
  • Eclipse中引入JUnit进行单元测试

    1.  在eclipse中添加junit.jar包 打开eclipse-菜单栏点击project-properties-Java Build Path-Libraries-Modulepath-Add External JARS-找到自己下载的junit.jar点击打开,即完成。 2. 在左侧的项目浏览器目录中就可以看到一个JUnit4的目录就引入进来了,如下图所示: 3. 我们新建一个测试类,在其中添加一

    2024年02月11日
    浏览(34)
  • IDEA使用Junit4进行单元测试

            单元测试不仅能帮我们验证代码逻辑,还可以通过执行时间进行快速筛选不合格代码并进行优化。核心模块的代码的单元测试覆盖率要达到100%,其他模块代码的单元测试覆盖率需要达到60%。下面将介绍在IDEA上使用Junit4进行单元测试的方法: 一、安装JunitGenerator2插件

    2023年04月16日
    浏览(44)
  • 在Idea中使用JUnit进行单元测试

    JUnit是Java中最常用的单元测试框架之一,它可以帮助开发人员编写高效、可靠的测试代码。在Idea集成开发环境中,我们可以方便地使用JUnit来编写和运行单元测试。本文将介绍如何在Idea中使用JUnit进行单元测试,并附带相应的源代码示例。 步骤一:添加JUnit依赖 首先,我们需

    2024年02月03日
    浏览(55)
  • 在eclipse里进行Junit单元测试并生成测试报告

    eclipse里自带Junit,不需要下载相应jar包,所以你只需要新建一个Java Project,在里面写你想要测试的java类文件就可以了。 首先,创建一个Java Project: 写一个计算器类Calculator作为要测试的类: 代码如下: 然后我们就可以来进行单元测试啦~ 这里选Junit4也是可以的,然后 Finish

    2024年02月05日
    浏览(41)
  • Junit4 + Mockito进行单元测试实战案例

    ​ 实战代码案例: ​​​​​​​​​​​ 注意:idea2021.3.3之前的版本都搜索不到这个插件。 使用TestMe自动生成单元测试代码: 不是自动化执行的单元测试都是无意义的,项目中那么多单测,难道一个一个点吗? 引入maven-surefire-plugin插件用于自动化执行单测。 include里表

    2024年02月16日
    浏览(53)
  • 在Idea中使用Junit4进行单元测试

    #初学者,为了对知识进行巩固写这个文章,有问题欢迎指出,欢迎讨论 在Setting - Plugins - Marketplace中搜索JUnit,点击Apply后重启Idea 创建的类和文件夹 按照这个顺序就可以啦 点击OK后,在我们的Test文件夹中就出现了一个测试文件

    2024年02月03日
    浏览(54)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包