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

news2025/2/25 17:13:01

文章目录

    • 概要
    • 首先看看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不支持依赖测试。JUnit和TestNG是两种流行的Java测试框架,用于测试Java应用程序中的代码。它们具有以下区别:

实践篇

摸拟业务逻辑代码

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

简单对象
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;
	}

	@Override
	public 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 {

	@Resource
	DemoDaoImpl 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
	@InjectMocks
	DemoTaskImpl demoTask;

	/**
	 * mock的类的中间传递类
	 */
	@Resource
	@InjectMocks
	DemoServiceImpl demoService;

	/**
	 * 被mock的类
	 */
	@Mock
	DemoDaoImpl demoDao;

	@Test
	public 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 {

	/**
	 * 测试入口类
	 */
	@Resource
	DemoTaskImpl demoTask;

	/**
	 * 被mock的类 选用spy方式  默认使用原生逻辑,仅mock的方法才被mock
	 */
	@SpyBean
	DemoDaoImpl demoDao;

	@Test
	public 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 {

	/**
	 * 测试入口类
	 */
	@Resource
	DemoTaskImpl demoTask;

	/**
	 * 被mock的类 选用spy方式  默认使用原生逻辑,仅mock的方法才被mock
	 */
	@SpyBean
	DemoDaoImpl demoDao;


	@Test
	public 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.coloradmin.cn/o/1148547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PyQt学习篇 · ⑥】:QWidget - 事件

文章目录 事件消息显示和关闭事件移动事件调整大小事件鼠标事件进入和离开事件鼠标按下和释放事件鼠标双击事件鼠标按下移动事件 键盘事件焦点事件拖拽事件绘制事件改变事件右键菜单输入法 事件转发机制案例一案例二案例三 事件消息 显示和关闭事件 showEvent(QShowEvent)方法…

Kubernetes - Ingress HTTP 升级 HTTPS 配置解决方案(新版本v1.21+)

之前我们讲解过 Kubernetes - Ingress HTTP 搭建解决方案&#xff0c;并分别提供了旧版本和新版本。如果连 HTTP 都没搞明白的可以先去过一下这两篇 Kubernetes - Ingress HTTP 负载搭建部署解决方案_放羊的牧码的博客-CSDN博客Kubernetes - Ingress HTTP 负载搭建部署解决方案…

7.scala方法初探

概述 在 scala 中&#xff0c;方法定义在内中&#xff0c;这点类似于 java &#xff0c;此文说明如何定义方法&#xff0c;及方法一些 用法 相关链接 阅读之前&#xff0c;可以先行浏览一下 官方文档 scala相关文章 定义一个参数的方法 这个例子定义了一个名为 double 方法&a…

会声会影2024这款视频剪辑软件怎么样?

众所周知&#xff0c;每每有新兴行业逐渐崛起壮大的时候&#xff0c;随机而来的就是这个行业创造出的衍生行业&#xff0c;比如说现在的短视频平台或者是视频剪辑行业&#xff0c;都是很明显的例子&#xff0c;今天我们就针对剪辑软件来和大家聊一聊&#xff0c;会声会影2024这…

Vue显示FFmpeg推的流

零、环境安装 小弟的另一篇文章&#xff1a; FFmpeg和rtsp服务器搭建视频直播流服务-CSDN博客 一、FFmpeg推流 1、拉取rtsp摄像头流 sudo ffmpeg -f v4l2 -input_format mjpeg -i /dev/video0 -c:v copy -f rtsp rtsp://10.168.3.196:8554/mystream2、推视频的rtmp流 sudo ffm…

Node学习笔记之user用户API模块

1、获取用户的基本信息 步骤 获取登录会话存储的session中用户的id判断是否获取到id根据用户id查询数据库中的个人信息检查指定 id 的用户是否存在将密码设置为空将数据返回给前端 // 获取用户信息数据 exports.userinfo (req, res) > {(async function () {// 1. 获取…

在CentOS上用yum方式安装MySQL8过程记录

此文参考官方文档一步一步记录安装到正常运行全过程 安装过程主要参考下面两边文章&#xff1a; 1.官方文档 https://dev.mysql.com/doc/refman/8.0/en/linux-installation-yum-repo.html 2.linux yum安装mysql8 安装过程大概有以下几步&#xff1a; 1.查找mysql源链接 2.安装…

框架安全-CVE 漏洞复现DjangoFlaskNode.jsJQuery框架漏洞复现

目录 服务攻防-框架安全&CVE复现&Django&Flask&Node.JS&JQuery漏洞复现中间件列表介绍常见语言开发框架Python开发框架安全-Django&Flask漏洞复现Django开发框架漏洞复现CVE-2019-14234&#xff08;Django JSONField/HStoreField SQL注入漏洞&#xff…

Proteus仿真--从左往右流水灯仿真(仿真文件+程序)

本文主要介绍基于51单片机的流水灯仿真&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真运行视频 Proteus仿真--基于51单片机的流水灯仿真&#xff08;从左往右&#xff09; 附完整Proteus仿真资料代码资料 百度网盘链接: https://pan.baidu.com/s/1aZH13zwQkNB7…

python自动化测试(七):鼠标事件

前置条件&#xff1a; 本地部署&#xff1a;ECShop的版本是3.0.0、Google版本是 Google Chrome65.0.3325.162 (正式版本) &#xff08;32 位&#xff09; py的selenium版本是3.11.0 目录 一、前置代码 二、ActionChains类 三、鼠标事件 3.1 悬停事件 3.2 左键单击 3…

2.flink编码第一步(maven工程创建)

概述 万里第一步&#xff0c;要进行flink代码开发&#xff0c;第一步先整个 flink 代码工程 flink相关文章链接 flink官方文档 两种方式 一种命令行 mvn 创建&#xff0c;另一种直接在 idea 中创建一个工程&#xff0c;使用 mvn 的一些配置 mvn命令行创建 mvn 创建flink工程&…

基于SpringBoot的工厂车间管理系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 人员管理 看板信息管理 设备信息管理 生产开立管理 人员功能实现 生产开立管理 生产工序管理 生产流程管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 社会发展日新月异&#xff0c;用计…

springboot整合postgresql

使用docker安装postgres 简单起见&#xff0c;这里用docker来安装postgresql docker pull postgresdocker run --name postgres \-e POSTGRES_PASSWORD123456 \-p 5432:5432 \-v /usr/local/docker/postgresql/data:/var/lib/postgresql/data \-d postgrespostgres客户端 pg…

MAC缓解WebUI提示词反推

当前环境信息&#xff1a; 在mac上安装好stable diffusion后&#xff0c;能做图片生成了之后&#xff0c;遇到一些图片需要做提示词反推&#xff0c;这个时候需要下载一个插件&#xff0c;参考&#xff1a; https://gitcode.net/ranting8323/stable-diffusion-webui-wd14-tagg…

计算机毕业设计选题推荐-二手交易微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

qt-C++笔记之带有倒计数显示的按钮,计时期间按钮锁定

qt-C笔记之带有倒计数显示的按钮&#xff0c;计时期间按钮锁定 code review! 文章目录 qt-C笔记之带有倒计数显示的按钮&#xff0c;计时期间按钮锁定1.运行2.main.cc3.main.pro 1.运行 2.main.cc 代码 #include <QApplication> #include <QPushButton> #includ…

day02 矩阵 2023.10.26

1.矩阵 2.矩阵乘法 3.特殊矩阵 4.逆矩阵 5.正交矩阵 6.几何意义 7.齐次坐标 8.平移矩阵 9.旋转矩阵 10.缩放矩阵 11.复合运算

vue3 动态组件和异步组件

1.动态组件 <template><div><h1>组件切换</h1><component :is"currentComponent"></component><button click"toggleComponent">点击切换组件</button></div> </template><script setup …

搜狗百科创建步骤

搜狗百科属于微信生态里的平台&#xff0c;搜狗百科不仅在搜狗搜索中展示&#xff0c;且可以在微信搜索中展示。许多个人、企业和品牌都希望在搜狗百科上创建属于自己的词条&#xff0c;以提高知名度和品牌形象。那么搜狗百科该怎么创建呢&#xff1f;下面小马识途营销顾问分享…

虚拟机Ubuntu下运行vue-element-admin项目

一.环境搭建 1.安装nodejs sudo apt install nodejs 安装完成后&#xff0c;查看对应的版本号 nodejs -v没有问题&#xff0c;会输出对应版本号&#xff0c;我这里是10.19.0 v10.19.0 2.安装npm sudo apt install npm安装完成查看对应的版本号&#xff0c;确认OK npm -…