首页 > 其他分享 >SpringBoot 测试实践 - 1:常用的工具

SpringBoot 测试实践 - 1:常用的工具

时间:2023-08-21 09:11:44浏览次数:43  
标签:SpringBoot List list 实践 测试 import Test org public

我自己接触到的一些商业或是开源的基于 SpringBoot 项目,它们大部分是没有测试代码的,test 文件夹只有脚手架初始化生成的那个测试类,跟不同的开发聊到这个话题,发现他们中的大部分没有写测试的习惯,或者是觉得写测试代码麻烦,主要还是依赖测试工程师做黑盒的测试。只做黑盒测试的话有一定的的局限性,一些比较***钻的案例可能就覆盖不到,而且相对来说人也比较容易出错、遗漏。而测试代码能解决其中很大一部分的问题,利用好单元测试和集成测试在某些情况下相对于直接通过 UI 进行测试是要更方便、节省时间的,所以想通过几篇博客来分享一下自己的测试实践

为什么要写测试(优点)

  1. 覆盖更多的边界条件,且随时都可以运行测试代码(一劳永逸)
  2. 缩小测试范围:测试某个方法只需要运行对应的测试代码,而不需要运行整个项目通过请求接口进行测试
  3. 对重构更友好,可以随时重构有集成测试的代码,不用担心打破原有的代码
  4. 其他人也可以通过测试快速地理清楚对应被测代码的主线逻辑(类似文档的作用,特别是复杂代码,通过测试能快速理解上手)
  5. 写测试的过程,给自己一个新的视角去审视代码结构的设计,有助于改善代码设计

当然代码方式的测试也并非完美无缺:测试代码增加编写和维护的成本,同时一些外部依赖也需要通过 Mock 的方式实现,这些都提高了整个测试编写的门槛。也倒逼我们思考更好地组织代码,减少依赖

另一个方面:测试对于重构也是至关重要的,随着对业务的理解越来越深刻,可以重构代码,抽象出了一些共性的逻辑,优化代码结构,但是如果没有相关测试,面对着旧代码就只能望而却步了

测试工具:JUnit 5, AssertJ,Mockito

spring-boot-starter-test 自带常用的测试工具:JUnit5AssertjMockito,可以直接使用

JUnit5

Junit 5 包含:

  • JUnit Platform:Test Engine
  • Jupiter:编程模型和拓展模型
  • Vintage:兼容老版本

JUnit 4 和 5 使用的包有所不同

// JUnit 4
import org.junit.Test;
import static org.junit.Assert.assertEquals;

// JUnit 5
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

如果不考虑兼容 JUnit 4 的测试,我们可以直接在依赖中直接排除 JUnit 4 的依赖,这样也可以避免在使用的时候错误地引入 JUnit 4 的包

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>{spring-boot-starter-test-version}</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

</dependencies>

还有一点值得注意的是:JUnit 5 中 @RunWith 被 @ExtendWith 代替

AssertJ

AssertJ 是一种支持链式编程的断言库,相对于 JUnit 自带的断言,它提供了更多的方法,也提供了更好的断言不匹配时的信息展示

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class MyTest {
    // 变量断言
    @Test
    public void test() {
        String name = "Alice";
        int age = 30;
        
        assertThat(name).isEqualTo("Alice");
        assertThat(age).isGreaterThan(18).isLessThan(60);
    }

    // List 断言
    @Test
    public void testList() {
        List<String> list = Arrays.asList("foo", "bar", "baz")
        assertThat(list).containsExactly("foo", "bar", "baz").hasSize(3);
    }

    // Map 断言
    @Test
    public void testMap() {
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 1);
        map.put("banana", 2);
        map.put("orange", 3);

        assertThat(map).containsEntry("banana", 2);

        assertThat(map).containsKey("banana");

        assertThat(map).containsValue(2);
    }

    // hasNoNullFieldsOrProperties 来断言测试对象的每个属性都不为 null
    @Test
    public void testHasNoNullFieldsOrProperties() {
        Person person = new Person("Alice", 30);
        assertThat(person).hasNoNullFieldsOrProperties();
    }

    // 异常断言
    @Test
    public void testDivideByZeroThrowsException() {
        assertThatThrownBy(() -> {
            int result = 1 / 0;
        }).isInstanceOf(ArithmeticException.class)
          .hasMessageContaining("/ by zero");
    }
}

Mockito

Mockito 是一个 Java Mock 框架,用于创建各种类型的 Mock 对象,并设置 Mock 对象的行为

import static org.mockito.Mockito.*;

import org.junit.jupiter.api.Test;

public class MyTest {
    // 创建 mock 对象
    @Test
    public void testCreateMock() {
        List<String> list = mock(List.class);
    }
    
    // 设置 mock 对象的行为
    @Test
    public void testMockBehavior() {
        List<String> list = mock(List.class);
        when(list.get(0)).thenReturn("foo");
        when(list.size()).thenReturn(1);
    }
    
    // 验证 mock 对象的方法调用
    @Test
    public void testMockVerification() {
        List<String> list = mock(List.class);
        list.add("foo");
        list.add("bar");
        verify(list).add("foo");
        verify(list).add("bar");
        // 验证调用方法的次数
        verify(list, times(2)).add(anyString());
    }

    // 模拟方法抛出异常
    @Test
    public void testMockException() {
        List<String> list = mock(List.class);
        doThrow(new RuntimeException()).when(list).clear();
        assertThrows(RuntimeException.class, () -> list.clear());
    }
}

也可以用注解来声明 Mock 对象,这样更清晰

import static org.mockito.Mockito.*;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

// 启用 Mockito 扩展
@ExtendWith(MockitoExtension.class)
public class MyMockitoTest {
    
    // 创建一个 List 类型的 Mock 对象
    @Mock
    List<String> mockList;
    
    // 使用 @InjectMocks,将会自动注入被测试类中所声明的 Mock 对象到这个对象中 
    @InjectMocks
    MyService myService;
    
    @Test
    public void testMock() {
        // 模拟 Mock 对象的行为
        when(mockList.get(0)).thenReturn("foo");
        when(mockList.size()).thenReturn(1);
        
        String result = myService.doSomething();
        
        assertEquals("foo", result);

        verify(mockList).get(0);
    }
}

class MyService {
    
    private List<String> list;
    
    public MyService(List<String> list) {
        this.list = list;
    }
    
    public String doSomething() {
        return list.get(0);
    }
}

参考资料

《重构 改善既有代码的设计》
有哪个开源项目,单元测试用例覆盖的比较全的?
业务代码写单元测试的最佳姿势是什么?
单元测试有落地效果好的团队吗?
Modern Best Practices for Testing in Java
Thoughts on efficient enterprise testing (1/6) - Sebastian Daschner

标签:SpringBoot,List,list,实践,测试,import,Test,org,public
From: https://www.cnblogs.com/aaronlinv/p/17645009.html

相关文章

  • 2.1 入门实践-一张普通报表
    一、普通报表1.概述1.1报表设计流程图1.2报表设计案例目标这张报表由三部分构成:参数面板:通过下拉框控件选择地区,查询出对应地区的数据。表格:表格统计该地区下各销售员每个产品的销量。柱形图:柱形图将表格中的数据以图表的形式进行展示。2.制作步骤2.1新建......
  • 网站压力测试 随机访问ip
    https://github.com/maintell/webBenchmarkhttp基准测试工具会耗尽您的服务器带宽。用户在使用本工具前请先查看授权及免责声明,webBenchmark一个用于测试网页服务器性能的工具,启用其他用途,后果自负。每个请求的随机用户代理可定制的引用网址,可定制的标题,您希望的并发例程取......
  • 浅谈软件产品质量模型与软件测试的关联关系
    为什么软件测试人员需要深入理解软件产品质量模型?软件测试人员在测试产品的过程中,就像一面镜子,需要照出系统的面貌,提供开发者修改代码的依据。而这个照镜子的过程就是对质量对评估的过程,测试人员需要对有效的质量评估负责,那就要求测试人员能充分的理解产品质量的概念,那么测试人......
  • 测试使用QT来连接SQLServer并取出表格数据
    测试使用QT来连接SQLServer并取出表格数据添加引用工程文件需要加入 QT+=sql在main.cpp添加头文件引用//添加头文件#include<qdebug.h>#include<QSqlDatabase>#include<QSqlError>#include<QSqlQuery>连接数据库QSqlDatabasedb=QSqlDatabase::addDatabase("QODBC");......
  • 【渗透测试】 Vulnhub JANGOW: 1.0.1
    渗透环境攻击机:   IP: 192.168.149.128(Kali)靶机:     IP:192.168.149.129靶机下载地址:https://www.vulnhub.com/entry/jangow-101,754/进行渗透一、获取IP及端口信息使用nmap扫描同网段IP,如果使用的是VMware可能出现扫描不到的情况,需要在靶机的恢复模式里......
  • Chia实践(二):安装Chia及使用cli
    前言某些价值上可能难以认同,例如Chia官方宣称的本该被销毁的硬盘用于耕种是有意义的。硬盘被销毁了,不再产生电力浪费,而继续运行还将持续,虽然相对于其他方式,已经好很多了。对于Chia,本身至少还是在持续进行中的。本文演示Chia在CentOS7Linux操作系统部署,在类似的操作系统都是可以......
  • Jmeter 接口测试工具入门
    1)Jmeter介绍JMeter是一款JAVA桌面应用程序,常常被用来做接口测试、负载测试等等JMeter是一款开源测试工具:开源免费软件,不需要任何使用费用小巧绿色,相比LoadRunner的庞大,它非常小巧并且不需要安装(需要安装JDK)功能强大,设计之初只是一个简单的性能测试工具,经过无数次更......
  • PHP调优策略和性能测试工具的详细解析 - 大规模网站性能优化
    当面临大规模网站性能优化时,对PHP进行调优是至关重要的。这涉及到评估现有系统的性能瓶颈,并采取适当的策略来提高网站的响应速度和吞吐量。本文将深入探讨PHP调优的策略,以及可用于性能测试的工具。1.PHP调优策略a.代码优化使用缓存:合理使用缓存可以减少数据库查询和计算操作......
  • 构建高效远程团队协作网络的最佳实践分享与经验总结
    随着全球化和科技发展的推进,越来越多的企业开始采用远程办公模式。构建高效远程团队协作网络成为了提高工作效率和团队凝聚力的关键。本文将分享一些构建高效远程团队协作网络的最佳实践和经验总结,帮助团队更好地远程协作。1.选择合适的协作工具选择适合团队需求的协作工具是构......
  • 我的性格之旅:深入探索_Big_Five_性格测试
    引言生活中的每个人都是一本独特的书。有时,我们对自己的性格和行为有所了解,有时却感到陌生。在探索自我性格的过程中,我发现了BigFive性格测试,一种深入分析个人特质的工具。下面,就让我带您走进这次探险之旅。第一章:BigFive性格模型的普及与误解1.1性格的五大维度BigFive......