关于测试组件junit切换testng的示例以及切换方式分享

文章目录

    • 概要
    • 首先看看junit和testng的区别
    • 实践篇
      • 摸拟业务逻辑代码
        • 简单对象
        • 数据层摸拟类
        • 业务逻辑层摸拟类
        • 后台任务摸拟类
      • 基于spring+mock+junit
      • 基于spring+mock+testng
    • 示例的差异点
        • junit与testng的主要变动不大,有以下几个点需要注意
        • 注解部分
        • 在before,after中
        • testng多出按配置执行功能
        • 附上关于mock 新旧写法改进
    • 小结

概要

本文作者之前写单元测试都是使用junit
场景有以下三种场景
仅junit
spring+junit
mock+spring+junit

本文会用第三种场景写简单的实例列出junit和testng的代码相关说明
并会将涉及的修改点一一说明
目的帮助大家了解testng及具体的切换方式

首先看看junit和testng的区别

JUnit和TestNG是两种流行的Java测试框架,用于测试Java应用程序中的代码。它们具有以下区别:

  1. 组织方式:JUnit使用Annotations来标注测试方法,而TestNG使用XML文件来组织测试。

  2. 支持的测试类型:JUnit 4支持单元测试,而TestNG支持功能测试、集成测试和端到端测试。

  3. 并发测试:TestNG支持并发测试,可以在同一时间运行多个测试用例,而JUnit不支持并发测试。

  4. 数据提供者:TestNG支持数据提供者,可以在不同参数上运行相同的测试用例,而JUnit不支持数据提供者。

  5. 测试套件:TestNG支持测试套件,可以组织不同的测试用例,而JUnit不支持测试套件。

  6. 依赖测试:TestNG支持依赖测试,可以在一组测试之前运行必需的测试,而JUnit不支持依赖测试。

实践篇

摸拟业务逻辑代码

场景,有三层以上代码层次的业务场景,需要摸拟最底层数据层代码

简单对象
package com.riso.junit;/*** DemoEntity* @author jie01.zhu* date 2023/10/29*/
public class DemoEntity implements java.io.Serializable {private long id;private String name;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "DemoEntity{" + "id=" + id + ", name='" + name + '\'' + '}';}}
数据层摸拟类
package com.riso.junit;import org.springframework.stereotype.Component;/*** DemoDaoImpl* @author jie01.zhu* date 2023/10/29*/
@Component
public class DemoDaoImpl {public int insert(DemoEntity demoEntity) {System.out.println("dao.insert:" + demoEntity.toString());return 1;}
}
业务逻辑层摸拟类
package com.riso.junit;import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** DemoServiceImpl* @author jie01.zhu* date 2023/10/29*/
@Service
public class DemoServiceImpl {@ResourceDemoDaoImpl demoDao;public int insert(DemoEntity demoEntity) {System.out.println("service.insert:" + demoEntity.toString());return demoDao.insert(demoEntity);}}
后台任务摸拟类
package com.riso.junit;import org.springframework.stereotype.Component;/*** DemoTaskImpl* @author jie01.zhu* date 2023/10/29*/
@Component
public class DemoTaskImpl {DemoServiceImpl demoService;public int insert(DemoEntity demoEntity) {System.out.println("task.insert:" + demoEntity.toString());return demoService.insert(demoEntity);}
}

基于spring+mock+junit

maven依赖

   <!-- test --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.12.4</version><scope>test</scope></dependency>
package com.riso.junit.test;import com.riso.junit.DemoDaoImpl;
import com.riso.junit.DemoEntity;
import com.riso.junit.DemoServiceImpl;
import com.riso.junit.DemoTaskImpl;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import javax.annotation.Resource;/***  junit test* @author jie01.zhu* date 2023/10/29*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}, inheritLocations = true)
public class Test1 {/*** 测试入口类*/@Resource@InjectMocksDemoTaskImpl demoTask;/*** mock的类的中间传递类*/@Resource@InjectMocksDemoServiceImpl demoService;/*** 被mock的类*/@MockDemoDaoImpl demoDao;@Testpublic void test1() {// 初始化mock环境MockitoAnnotations.openMocks(this);DemoEntity demoEntity = new DemoEntity();demoEntity.setId(1L);demoEntity.setName("name1");Mockito.doReturn(0).when(demoDao).insert(Mockito.any());int result = demoTask.insert(demoEntity);Assert.assertEquals(result, 0);}
}

基于spring+mock+testng

有二个测试类,测试参数不同,主要体现在单元测试外,控制二个测试类,按并发场景做简单的集成测试

maven依赖

        <dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>6.14.3</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><version>2.4.13</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.12.4</version><scope>test</scope></dependency>
package com.riso.testng.test;import com.riso.testng.ContextConfig;
import com.riso.testng.DemoDaoImpl;
import com.riso.testng.DemoEntity;
import com.riso.testng.DemoTaskImpl;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.Test;import javax.annotation.Resource;/***  junit test* @author jie01.zhu* date 2023/10/29*/
@SpringBootTest(classes = {ContextConfig.class})
@TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
public class Test1 extends AbstractTestNGSpringContextTests {/*** 测试入口类*/@ResourceDemoTaskImpl demoTask;/*** 被mock的类 选用spy方式  默认使用原生逻辑,仅mock的方法才被mock*/@SpyBeanDemoDaoImpl demoDao;@Testpublic void test1() {// 初始化mock环境MockitoAnnotations.openMocks(this);DemoEntity demoEntity = new DemoEntity();demoEntity.setId(1L);demoEntity.setName("name1");Mockito.doReturn(0).when(demoDao).insert(Mockito.any());int result = demoTask.insert(demoEntity);Assert.assertEquals(result, 0);}
}package com.riso.testng.test;import com.riso.testng.ContextConfig;
import com.riso.testng.DemoDaoImpl;
import com.riso.testng.DemoEntity;
import com.riso.testng.DemoTaskImpl;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.Test;import javax.annotation.Resource;/***  junit test* @author jie01.zhu* date 2023/10/29*/
@SpringBootTest(classes = {ContextConfig.class})
@TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
public class Test2 extends AbstractTestNGSpringContextTests {/*** 测试入口类*/@ResourceDemoTaskImpl demoTask;/*** 被mock的类 选用spy方式  默认使用原生逻辑,仅mock的方法才被mock*/@SpyBeanDemoDaoImpl demoDao;@Testpublic void test2() {// 初始化mock环境MockitoAnnotations.openMocks(this);DemoEntity demoEntity = new DemoEntity();demoEntity.setId(2L);demoEntity.setName("name2");Mockito.doReturn(2).when(demoDao).insert(Mockito.any());int result = demoTask.insert(demoEntity);Assert.assertEquals(result, 2);}
}

testNg的 配置文件,也是执行入口

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="test" parallel="tests" thread-count="2"><test name="test1" group-by-instances="true"><classes><class name="com.riso.testng.test.Test1"/></classes></test><test name="test2" group-by-instances="true"><classes><class name="com.riso.testng.test.Test2"></class></classes></test>
</suite>

运行方式如下:
在这里插入图片描述

示例的差异点

junit与testng的主要变动不大,有以下几个点需要注意
注解部分

junit此处注解
@RunWith(SpringJUnit4ClassRunner.class)
testng不再使用此注解
需要继承 org.springframework.test.context.testng.AbstractTestNGSpringContextTests

在before,after中

testng完全兼容,但会多出Suite ,它代替xml配置中,单元测试类之上的生命周期

testng多出按配置执行功能

首先testng的单元测试可以与junit一样,单独运行
在这个基础上,也能通过testng xml按配置运行,可以见上面的例子

附上关于mock 新旧写法改进

以前要摸拟调用对象的跨二层以上类时,需要通过InjectMocks 做为中间传递,才能成功mock掉二层以上的类
换成spyBean后,不需要再使用InjectMocks ,会自动从注入中找到
这个小插曲也是我自己对以前mock的修正,一并附上

小结

通过以上说明,及示例
testng是完全兼容junit的,且改动很小
注解,断言都是直接兼容的(只需要更换导入的包路径既可)

当然,我不是为了使用而使用,一切都要建立上有需求的基础上
junit对我来讲,已经满足不了我的需求,
为了能够编写集成测试,同时复用已有的单元测试,我选择了testng
希望以上分享,能够对读者有用.

朱杰
2023-10-29

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/175907.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为数通方向HCIP-DataCom H12-831题库(多选题:101-120)

第101题 LSR对收到的标签进行保留,且保留方式有多种,那么以下关于LDP标签保留一自由方式的说法 A、保留邻居发送来的所有标签 B、需要更多的内存和标签空间 C、只保留来自下一跳邻居的标签,丢弃所有非下一跳铃邻居发来的标签 D、节省内存和标签空间 E、当IP路由收敛、下一跳…

verilog语言学习

1. 时延 2. 一位全加器设计&#xff1a;三种建模方式 实际的设计中往往是这三种设计模式的混合 3. 4. 5. 6. 7. 建立模型时信号的连接&#xff08;重点&#xff09; 8. initial语句 9. always语句 在always中不能同时判断同一个信号的上升沿&#xff08;posedge&#xff0…

简单明了!网关Gateway路由配置filters实现路径重写及对应正则表达式的解析

问题背景&#xff1a; 前端需要发送一个这样的请求&#xff0c;但出现404 首先解析请求的变化&#xff1a; http://www.51xuecheng.cn/api/checkcode/pic 1.请求先打在nginx&#xff0c;www.51xuecheng.cn/api/checkcode/pic部分匹配到了之后会转发给网关进行处理变成localho…

软件测试之BUG篇(定义,创建,等级,生命周期)

目录 1. BUG 的定义 2. 如何创建 BUG 3. BUG 等级 4. BUG 生命周期 高频面试题&#xff1a; 1. BUG 的定义 当且仅当产品规格书存在且正确时&#xff0c;程序的实现和规格书的要求不匹配时&#xff0c;那就是软件错误。当产品规格说明书没有提到的功能时&#xff0c;以用户…

如何使用drawio画流程图以及导入导出

画一个基本的流程图 你可以在线使用drawio, 或者drawon创建很多不同类型的图表。 如何使用编辑器&#xff0c;让我们以一个最基本的流程图开始。 流程图&#xff0c;就是让你可视化的描述一个过程或者系统。 图形和很少部分的文字表达就可以让读者很快的理解他们需要什么。 创…

如何看待2023年大量劝入C++?

如何看待2023年大量劝入C&#xff1f; 这一段陆陆续续很多人关注这个话题&#xff0c;想提醒大家&#xff0c;c真的很看重领域行业经验&#xff0c;在这里&#xff0c;c只是个工具&#xff0c;相反是这个行业的知识更重要&#xff0c; 最近很多小伙伴找我&#xff0c;说想要一…

制作一个简单的C语言词法分析程序

1.分析组成 C语言的程序中&#xff0c;有很单词多符号和保留字。一些单词符号还有对应的左线性文法。所以我们需要先做出一个单词字符表&#xff0c;给出对应的识别码&#xff0c;然后跟据对应的表格来写出程序 2.程序设计 程序主要有循环判断构成。不需推理即可产生的符号我…

【机器学习可解释性】4.SHAP 值

机器学习可解释性 1.模型洞察的价值2.特征重要性排列3.部分依赖图4.SHAP 值5.SHAP值的高级使用 正文 理解各自特征的预测结果&#xff1f; 介绍 您已经看到(并使用)了从机器学习模型中提取一般解释技术。但是&#xff0c;如果你想要打破模型对单个预测的工作原理? SHAP 值…

大促期间如何应对低价链接

一年一度的大促双十一即将来临&#xff0c;品牌商、经销商在忙着出货&#xff0c;消费者也在积极比价&#xff0c;大促最直观的感觉就是价格&#xff0c;没有低价的大促是没有意义的&#xff0c;所以品牌要管的不是低价产品&#xff0c;而是在不受规则下的低价行为。 力维网络有…

maven:编译出现Process terminated解决方法(超全)

maven:编译出现Process terminated解决方法&#xff08;超全&#xff09; 一. 情况一&#xff1a;配置文件 settings. xml 出错&#xff08;解决方法1&#xff09;1.1 项目编译报错如下&#xff1a;1.2 点击【项目名】提示找到出错文件1.3 点击查看出错文件1.4 原因及解决办法 …

Matlab论文插图绘制模板第123期—水平正负柱状图

在之前的文章中&#xff0c;分享了很多Matlab柱状图的绘制模板&#xff1a; 进一步&#xff0c;再来看一种特殊的柱状图&#xff1a;水平正负柱状图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下…

省钱兄短剧短视频视频滑动播放模块源码支持微信小程序h5安卓IOS

# 开源说明 开源省钱兄短剧系统的播放视频模块&#xff08;写了测试弄了好久才弄出来、最核心的模块、已经实战了&#xff09;&#xff0c;使用uniapp技术&#xff0c;提供学习使用&#xff0c;支持IOSAndroidH5微信小程序&#xff0c;使用Hbuilder导入即可运行 #注意&#xff…

[红蓝攻防]MDOG(全新UI重制版)为Xss跨站而生,数据共享,表单劫持,URL重定向

项目:https://github.com/MartinxMax/MDOG 说明 功能Cookie窃取表单劫持(钓鱼账密)重定向流量劫持多平台数据推送钉钉数据推送 运行窗口 ./dist目录下已生成exe文件,双击打开 Cookie窃取 点击运行服务,复制以上的payload,payload怎么变形那么你可已去混淆 payload在页面执…

chatgpt论文润色 降重

用chatgpt最好要给他范例。chatgpt降重原理&#xff1a; https://www.bilibili.com/video/BV1Eh411M7Ug/?spm_id_from333.337.search-card.all.click&vd_sourceebc47f36e62b223817b8e0edff181613 一. 中文论文翻译成英文 广义零样本学习是我的研究方向&#xff0c;下面…

网络爬虫适合什么代理IP?如何使用?

在互联网时代之下&#xff0c;大数据对各行各业的发展有着重要的推动作用&#xff0c;而说到数据采集&#xff0c;必不可少的就是去使用爬虫工作。 一、什么是网络爬虫&#xff1f; 它是一种按照一定的规则自动游览、检索网页信息的程序或者脚本&#xff0c;通过自动请求目标…

路由器如何设置IP地址

IP地址是计算机网络中的关键元素&#xff0c;用于标识和定位设备和主机。在家庭或办公室网络中&#xff0c;路由器起到了连接内部设备和外部互联网的关键作用。为了使网络正常运行&#xff0c;需要正确设置路由器的IP地址。本文将介绍如何设置路由器的IP地址&#xff0c;以确保…

C++设计模式_19_Memento 备忘录(理解,目前多使用序列化方案来实现)

Memento 备忘录模式也属于“状态变化”模式&#xff0c;它是一个小模式&#xff0c;在今天来看有些过时&#xff0c;当今已经很少使用当前模式实现需求&#xff0c;思想却不变&#xff08;信息隐藏&#xff09;&#xff0c;目前多使用序列化方案来实现。本系列所介绍的模式&…

【C++笔记】C++多态

【C笔记】C多态 一、多态的概念及实现1.1、什么是多态1.2、实现多态的条件1.3、实现继承与接口继承1.4、多态中的析构函数1.5、抽象类 二、多态的实现原理 一、多态的概念及实现 1.1、什么是多态 多态的概念&#xff1a; 在编程语言和类型论中&#xff0c;多态&#xff08;英…

通讯网关软件031——利用CommGate X2HTTP实现HTTP访问ODBC数据源

本文介绍利用CommGate X2HTTP实现HTTP访问ODBC数据源。CommGate X2HTTP是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现上位机通过HTTP来获取ODBC数据源的数据。 【解决方案】设置网关机…

【设计模式】第12节:结构型模式之“外观模式”

一、简介 门面模式&#xff0c;也叫外观模式&#xff0c;英文全称是Facade Design Pattern。门面模式为子系统提供一组统一的接口&#xff0c;定义一组高层接口让子系统更易用。 目的&#xff1a;简化复杂系统的交互方式 特点&#xff1a;提供一个统一的交互接口 二、UML类…