Java开发 - Spring Test知多少?

简介: 在前文中,我们也使用了测试代码来进行简单的单元测试,但是我们会发现,里面有大量的重复代码,实际给我们的体验并不是太好,所以这篇,我们来学习Spring Test,Spring Test不仅仅限于在Mybatis框架,只要是基于Spring的框架的都可以使用Spring Test,使用Spring Test,将给测试模块带来质的改善,大大提高了自测的效率。接下来,我们就来学习Spring Test的用法和注意事项吧。

前言

在前文中,我们也使用了测试代码来进行简单的单元测试,但是我们会发现,里面有大量的重复代码,实际给我们的体验并不是太好,所以这篇,我们来学习Spring Test,Spring Test不仅仅限于在Mybatis框架,只要是基于Spring的框架的都可以使用Spring Test,使用Spring Test,将给测试模块带来质的改善,大大提高了自测的效率。接下来,我们就来学习Spring Test的用法和注意事项吧。

Spring Test的作用

在普通测试环境下,我们在使用Spring的时候,需要手动加载Spring配置,手动从Spring容器中获取对象,前文中的使用全是如此,这也就违背了我们使用Spring框架的意愿:自动创建对象,自动管理对象。我们把这种用法叫自动装配。

Spring还有一个用处,使用@Sql注解,此注解可在测试类方法之前定义,提前或延后执行某段sql语句,在测试中也经常使用。

在项目中加入Spring Test

添加依赖

<!--Spring Test依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.14</version>
        </dependency>

Spring Test无法单独工作,仍需配合其他测试依赖项和其他Spring依赖一起使用,可参照Mybatis一文中的依赖进行添加,亦可在原项目中直接操作。但要注意,要和其他Spring依赖项的版本保持一致,切记。

创建测试类

package cn.codingfire.mybatis;
public class MybatisTest {
}

此时需在测试类上添加@SpringJUnitConfig注解:

package cn.codingfire.mybatis;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@SpringJUnitConfig(SpringConfig.class)
public class MybatisTest {
}

接着我们可以在此类中添加Spring的配置类,这样,在此类中任何方法之前,都会先加载Spring的配置类,Spring容器中存在的类就都可以实现自动装配了。我们以环境变量为例:

package cn.codingfire.mybatis;
import cn.codingfire.mybatis.config.SpringConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@SpringJUnitConfig(SpringConfig.class)
public class MybatisTest {
    @Autowired
    Environment env;
    @Test
    public void testEnvironment() {
        System.out.println(env.getProperty("datasource.url"));
        System.out.println(env.getProperty("datasource.driver"));
        System.out.println(env.getProperty("datasource.username"));
        System.out.println(env.getProperty("datasource.password"));
    }
}

接着运行此测试方法,查看输出:

编辑

已经成功输出了我们在properties文件中配置的信息。对比之前Mybatis中的测试方法如下:

@Test
    public void loadBasicInfo() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        ConfigurableEnvironment environment = ac.getEnvironment();
        System.out.println(environment.getProperty("datasource.url"));
        System.out.println(environment.getProperty("datasource.driver"));
        System.out.println(environment.getProperty("datasource.username"));
        System.out.println(environment.getProperty("datasource.password"));
        ac.close();
    }

先获取ac,再获取environment,最后再关闭ac,简化了太多步骤。使用Spring Test,我们只需关注测试的内容本身,而不用去管环境的问题,效果要更好。再增删改查时也不需要再关注开头和结尾的那几段代码,这种重复性的操作被省略,也是自动装配的精髓之一。

关于@Autowired注解,就是自动装配的意思,我们可以尝试着给其他的对象添加此注解:

编辑

会看到AdminMapper报一个错,这里有个小知识点。这是因为编译器问题导致无法识别,解决办法是在AdminMapper的类中添加@Repository注解,回来后再看,正常来说报错会消失,但有的人的不会消失,可在注解里添加required属性为false:

编辑

此时,问题已经解决了,它的意思是,能装配上就装,不能装配也不强求。有意思的是,即使你不管这个报错,方法也可正常运行,不存在任何影响。

Spring Test下的测试方法

我们以插入方法为例,做个前后对比。

未使用Spring Test的插入方法测试:

@Test
    public void testInsert() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        AdminMapper adminMapper = ac.getBean(AdminMapper.class);
        Admin admin = new Admin();
        admin.setUsername("admin04");
        admin.setPassword("123456");
        adminMapper.insert(admin);
        ac.close();
    }

使用了Spring Test的插入方法测试 :

@Test
    public void testInsert() {
        Admin admin = new Admin();
        admin.setUsername("admin04");
        admin.setPassword("123456");
        adminMapper.insert(admin);
    }

前后对比明显,自动装配后,adminMapper由系统创建管理,可在类中直接使用,简化了代码。

@Sql注解

@Sql注解的作用和注意事项

Spring Test测试类中,还可以使用@Sql注解,他可以加载某些脚本.sql的脚本,可以在测试前后执行一些给定的sql语句。它的作用是可以在测试时进行反复测试,在Mybatis中,我们在测试时,有时为了使mapper的方法运行成功,需要运行插入的方法,这就很不友好了,增加了测试的成本,比如我删除某条数据后,表中没有数据,我要再执行删除操作前,必须要再插入一条数据,否则会报错,而我使用@Sql注解,就可以解决这个问题,使得每次测试不需要再关注其他的方法。

使用此注解要注意几个问题:

  • @Sql注解可以添加在单独的方法中,仅对此方法有效,也可添加在测试类上,对类中所有的方法有效。如果类和方法上都添加了相同的@Sql注解,仅方法上的生效
  • 可方法前执行.sql脚本,也可方法后执行.sql脚本,通过executionPhase属性来管理
  • @Sql注解可添加多个

@Sql注解怎么用

首先,我们需要先创建一个.sql文件,选择file,创建一个truncate.sql:

编辑

在test下的resoutces文件中创建,在此文件中可以看到和再sql工具中一样,是有sql提醒的。 truncate的意思是截断,在sql中意味着清空整张表。我们知道,数据库表中不允许插入相同的两条数据,否则就会报重复的错误,使用此注解,在每次插入前都清空整张表就可以频繁测试,看代码:

@Sql(scripts = {"classpath:truncate.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
    @Test
    public void testInsert() {
        Admin admin = new Admin();
        admin.setUsername("admin04");
        admin.setPassword("123456");
        adminMapper.insert(admin);
    }

可以在插入前清空整张表,以达到频繁插入的测试。

以删除为例,我们想删除的时候数据库表中一直有数据。此时,也可以使用此注解,接下来我们来说说怎么同时使用多个.sql脚本,首先创建一个插入的.sql脚本:

编辑

看代码:

@Sql(scripts = {"classpath:truncate.sql", "classpath:insert.sql"})
    @Test
    public void testDelete() {
        adminMapper.deleteById(1L);
    }

每次执行次方法都是成功的。如果你想在方法执行后再执行某些sql的话,可以设置@Sql的executionPhase属性为Sql.ExecutionPhase.AFTER_TEST_METHOD:

executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD

断言

我们通常在测试类中使用Assertions类的静态方法对测试结果进行预测,帮助我们发现代码中可能存在的问题,一旦不符合预测的正确结果就会报错,大大提高代码的正确性。常用的一些断言方法有:

  • assertEquals():断言匹配(相等)
  • assertNotEquals():断言不匹配(不相等)
  • assertTrue():断言为“真”
  • assertFalse():断言为“假”
  • assertNull():断言为null
  • assertNotNull():断言不为null
  • assertThrows():断言抛出异常
  • assertDoesNotThrow():断言不会抛出异常
  • 其他

接下来我们挑几个在代码中来看使用效果。

assertEquals():

@Sql(scripts = {"classpath:truncate.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
    @Test
    public void testInsert() {
        Admin admin = new Admin();
        admin.setUsername("admin04");
        admin.setPassword("123456");
        int index = adminMapper.insert(admin);
        System.out.println(index);
        Assertions.assertEquals(1,index);
    }

Assertions.assertEquals 有两个参数,第一个是expected,是期望的值,第二个是ectual,是实际的值,如果预测的不对,就会报错,正确则没有任何反应。

assertTrue()

还以插入为例,看代码:

@Sql(scripts = {"classpath:truncate.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
    @Test
    public void testInsert() {
        Admin admin = new Admin();
        admin.setUsername("admin04");
        admin.setPassword("123456");
        int index = adminMapper.insert(admin);
        System.out.println(index);
        boolean isThanZero = index > 0 ? true : false;
        Assertions.assertTrue(isThanZero);
    }

断言isThanZero,即影响的行数大于0,则说明插入成功,否则将报异常。

assertNull()

以根据id获取数据为例:

@Test
    public void getById() {
        Admin admin = adminMapper.getById(10L);
        Assertions.assertNull(admin);
    }

id为10的数据表中没有,所以语言admin为null,是正确的,符合我们的预期,不会报错。

assertThrows()

前面我们说过重复插入数据会把哦重复插入的异常,这时就不能在插入前清空表了,我们以此为例,看代码:

@Test
    public void testInsert() {
        Admin admin = new Admin();
        admin.setUsername("admin04");
        admin.setPassword("123456");
        Assertions.assertThrows(DuplicateKeyException.class, () -> {
            adminMapper.insert(admin);
        });
    }

正常来说,连续执行两次,就会抛出重复插入的异常,但是我们做了断言后,就不会有任何输出,反而会在第一次执行时抛出下面这段异常:

org.opentest4j.AssertionFailedError: Expected org.springframework.dao.DuplicateKeyException to be thrown, but nothing was thrown.

意思是说,我们预测会抛出重复的异常,但是什么也没有抛出。这是正常的,因为第一次插入成功了。

到这里,断言就写完了,上面列出来的每一类中的一个都给出了案例 ,照葫芦画瓢,对另一个取反就是另一个,相信聪明如大家已经知道该怎么用了,不再赘述。

结语

最近几天,这篇算是最短的了,写起来也最省劲,用了不到半天就写完了,虽然简单,但是里面的知识却很重要,最好结合前面的SSM框架一起来看和使用,可以达到事半功倍的效果。代码要练习,光看是不行的,不上手,就看不到输出,就容易忽略一些细节,希望大家都能学的贼溜,明年拿高薪。

目录
相关文章
|
2月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
287 3
|
1月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
3167 45
|
1月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
2月前
|
人工智能 Java API
构建基于Java的AI智能体:使用LangChain4j与Spring AI实现RAG应用
当大模型需要处理私有、实时的数据时,检索增强生成(RAG)技术成为了核心解决方案。本文深入探讨如何在Java生态中构建具备RAG能力的AI智能体。我们将介绍新兴的Spring AI项目与成熟的LangChain4j框架,详细演示如何从零开始构建一个能够查询私有知识库的智能问答系统。内容涵盖文档加载与分块、向量数据库集成、语义检索以及与大模型的最终合成,并提供完整的代码实现,为Java开发者开启构建复杂AI智能体的大门。
1435 58
|
1月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
126 8
|
2月前
|
监控 Java 数据库
从零学 Dropwizard:手把手搭轻量 Java 微服务,告别 Spring 臃肿
Dropwizard 整合 Jetty、Jersey 等成熟组件,开箱即用,无需复杂配置。轻量高效,启动快,资源占用少,内置监控、健康检查与安全防护,搭配 Docker 部署便捷,是构建生产级 Java 微服务的极简利器。
289 3
|
2月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
2月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
124 0
|
Java 开发工具 git
Java开发初级6.24.3
5.在Git使用过程中,进行Git配置的操作命令是哪个() A. config B. config -g C. config -a D. git config 相关知识点: 在git中,经常使用git config 命令用来配置git的配置文件,git配置级别主要有:仓库级别 local 【优先级最高】、用户级别 global【优先级次之】、系统级别 system【优先级最低】 正确答案:D 10.RDBMS是什么? A. Rela Database Management Systems B. Relational Database Management Systems C. Relation
213 0
|
SQL 前端开发 JavaScript
Java开发初级6.24.2
3.Java网站src/main/java目录保存的是什么资源? A. Java源代码文件 B. 测试代码 C. JavaScript、CSS等文件 D. 图片资源 正确答案:A 4.什么是索引Index? A. SQL数据库里的表管理工具 B. SQL数据库里的查询工具 C. SQL数据库里的目录工具 D. SQL数据库用来加速数据查询的特殊的数据结构 正确答案:D
291 0