Java Testcontainers库实现测试功能

1.Testcontainers介绍:

Testcontainers是一个Java库,它支持JUnit测试,提供公共数据库、SeleniumWeb浏览器或任何可以在Docker容器中运行的轻量级、一次性实例。

测试容器使以下类型的测试更加容易:

数据访问层集成测试:

使用MySQL,PostgreSQL或Oracle数据库的容器化实例测试您的数据访问层代码,但无需在开发人员的计算机上进行复杂的设置,并且测试将始终从已知的数据库状态开始,避免“垃圾”数据的干扰。也可以使用任何其他可以容器化的数据库类型。

应用程序集成测试:

用于在具有相关性(例如数据库,消息队列或Web服务器)的短期测试模式下运行应用程序。

UI /验收测试:

使用与Selenium兼容的容器化Web浏览器进行自动化UI测试。每个测试都可以获取浏览器的新实例,而无需担心浏览器状态,插件版本或浏览器自动升级。您将获得每个测试会话或测试失败的视频记录。

更多:

可以签出各种贡献的模块,或使用 GenericContainer作为基础创建自己的自定义容器类。

2.Testcontainers实践示例:

Testcontainers提供了多种现成的与测试关联的应用程序容器,如下图:

在本文中,将演示集成postgresql容器和mockserver容器的测试。

Testcontainers必要条件:

1.Docker

2.支持的JVM测试框架:JUnit4,JUnit5,spock...

2.1 集成postgresql测试依赖:

<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>testcontainers</artifactId>
  <version>1.12.5</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.testcontainers</groupId>
 	<!--指定数据库名称,mysql,mariadb等等-->
  <artifactId>postgresql</artifactId>
  <version>1.12.5</version>
  <scope>test</scope>
</dependency>

配置:

在项目的src/test/resources/application.properties文件中配置postgresql相关信息

#将驱动程序设置为org.testcontainers.jdbc.ContainerDatabaseDriver,它是一个Testcontainers JDBC代理驱动程序。初始化数据源时,此驱动程序将负责启动所需的Docker容器。
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver

#将JDBC URL设置为JDBC:tc:<database image>:<version>:///以便Testcontainers知道要使用哪个数据库。
#TC_INITSCRIPT=指定的数据库初始化的脚本文件位置
spring.datasource.url=jdbc:tc:postgresql:9.6:///?TC_INITSCRIPT=file:src/main/resources/init_db.sql

#将方言明确设置为数据库的方言实现,否则在启动应用程序时会收到异常。当您在应用程序中使用JPA时(通过Spring Data JPA),此步骤是必需的
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect

测试示例:

为了在@DataJpaTest中使用TC,您需要确保使用了应用程序定义的(自动配置的)数据源。您可以通过使用@AutoConfigureTestDatabase注释测试来轻松完成此操作,如下所示:

@RunWith(SpringJUnit4ClassRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class OwnerRepositoryTests {

  @Autowired
  private OwnerRepository ownerRepository;

  @Test
  void findAllReturnsJohnDoe() { // as defined in tc-initscript.sql
    var owners = ownerRepository.findAll();
    assertThat(owners.size()).isOne();
    assertThat(owners.get(0).getFirstName()).isEqualTo("John");
    assertThat(owners.get(0).getLastName()).isEqualTo("Doe");
  }
}

以上测试将使用Testcontainers提供的postgresql容器进行测试,从而排除了外部环境对测试的干扰。

当需要用本地数据库进行集成测试时,我们只要使用@SpringBootTest替换如上两个注解即可:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class OwnerResourceTests {

  @Autowired
  WebApplicationContext wac;

  @Test
  void findAllReturnsJohnDoe() throws Exception {
    given()
        .webAppContextSetup(wac)
    .when()
        .get("/owners")
    .then()
        .status(HttpStatus.OK)
        .body(
            "_embedded.owners.firstName", containsInAnyOrder("John"),
            "_embedded.owners.lastName", containsInAnyOrder("Doe")
        );
  }
}

以上测试将使用真实运行环境的数据库进行测试。

2.2 集成mockServer测试

Mock Server可用于通过将请求与用户定义的期望进行匹配来模拟HTTP服务。

依赖:

	<dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>mockserver</artifactId>
      <version>1.12.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mock-server</groupId>
      <artifactId>mockserver-netty</artifactId>
      <version>5.5.4</version>
    </dependency>
    <dependency>
      <groupId>org.mock-server</groupId>
      <artifactId>mockserver-client-java</artifactId>
      <version>5.5.4</version>
    </dependency>

测试示例:

//创建一个MockServer容器
@Rule
public MockServerContainer mockServer = new MockServerContainer();

以及使用Java MockServerClient设置简单的期望。

new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort())
        .when(request()
            .withPath("/person")
            .withQueryStringParameter("name", "peter"))
        .respond(response()
            .withBody("Peter the person!"));
//...当一个get请求至'/person?name=peter' 时会返回 "Peter the person!"

测试(使用restassured进行测试):

RestAssured.baseURI = "http://" + mockServer.getContainerIpAddress();
RestAssured.port = mockServer.getServerPort();
given().queryParam("name", "peter")
        .get("/person")
        .then()
        .statusCode(HttpStatus.OK.value())
        .body(is("Peter the person!"));

完整代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
public class OneTests {
  @Rule
  public MockServerContainer mockServer = new MockServerContainer();

  @Test
  public void v() {
    RestAssured.baseURI = "http://" + mockServer.getContainerIpAddress();
    RestAssured.port = mockServer.getServerPort();

    new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort())
        .when(request()
            .withPath("/person")
            .withQueryStringParameter("name", "peter"))
        .respond(response()
            .withBody("Peter the person!"));

    given().queryParam("name", "peter")
        .get("/person")
        .then()
        .statusCode(HttpStatus.OK.value())
        .body(is("Peter the person!"));
  }
}

3.总结:

Testcontainers轻松的解决了集成测试时测试代码与本地组件耦合,从而出现各种意外失败的问题(比如本地数据库中存在脏数据影响到了集成测试,多个集成测试同时运行时相互干扰导致测试结果意外失败)。笔者之前专门为集成测试准备了一套数据库,使数据和其他环境隔离掉,但还是会遇到多个集成测试一起跑相互干扰的问题,Testcontainers轻松的解决了笔者的问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java四舍五入时保留指定小数位数的五种方式

    方式一: double f = 3.1516; BigDecimal b = new BigDecimal(f); double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 输出结果f1为 3.15: 源码解读: public BigDecimal setScale(int newScale, int roundingMode) //int newScale 为小数点后保留的位数, int roundingMode 为变

  • 谈谈你可能并不了解的java枚举

    前言 枚举在java里也算个老生长谈的内容了,每当遇到一组需要类举的数据时我们都会自然而然地使用枚举类型: public enum Color { RED, GREEN, BLUE, YELLOW; public static void main(String[] args) { Color red = Color.RED; Color redAnother = Color.RED; Color blue = Color.BLUE; System.out.println(red.equals(r

  • Java 实现跨平台的操作方式

    什么是平台无关性 平台无关性就是一种语言在计算机上的运行不受平台的约束,一次编译,到处执行. 也就是说,用Java创建的可以执行二进制程序,能够不加改变的运行于多个平台,Java减少了开发和部署的多个平台的成本和时间. 平台无关性的实现 其中扮演者重要的角色有Java语言规范.Class文件.Java虚拟机(JVN)等. 在计算机世界中,计算机只认识0和1.所以,真正被执行的其实是由0和1组成的二进制文件. 日常开发使用的C.C++.Java.python 都属于是高级语言,而非二进制语言,所以

  • java中spi使用详解

    一.简介 java中spi(service provider interface)是jdk内置的一种服务发现机制,可以基于配置,在运行时加载指定服务.java中提供了很多服务提供接口,如jdbc.jndi等. 1.什么是SPI SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件. SPI的作用就是为这些被扩展的API寻找服务实现. 2.SPI和API的使用场景 API (Application Pr

  • Java实现五子棋的基础方法

    本文实例为大家分享了Java实现五子棋的具体代码,供大家参考,具体内容如下 任务概述: 五子棋是全国智力运动会竞技项目之一,是一种两人对弈的纯策略型棋类游戏.通常双方分别使用黑白两色的棋子,下在棋盘直线与横线的交叉点上,先形成五子连线者获胜. 任务过程: 1.绘制棋盘 2.提示黑方(用 1 表示)和白方(用 2 表示)分别下棋(X,Y 轴位置)并重新绘制棋盘 3.每当一方下棋后判断是否获胜 重点讲解: 1.关于胜利的判断: 根据用户所下棋子的位置对其周围进行检测,分为以下情况: 横向:当前下棋位

  • 浅谈java中的声明常量为什么要用static修饰

    今天定义一个类常量,想着也只有这个类可以用到,就没用static关键字修饰.结果sonar代码检查提示: Rename this field "PERSON_TYPE_USER" to match the regular expression '^[a-z][a-zA-Z0-9]*$'. 我一想我这是正确的命名规范啊,于是百度一搜这提示,发现前面加个static关键字修饰就可以了. 那么问题来了,我就当前类要使用,不需要设置成全局常量也可以,用static修饰常量有什么好处? 好处就是

  • Java Testcontainers库实现测试功能

    1.Testcontainers介绍: Testcontainers是一个Java库,它支持JUnit测试,提供公共数据库.SeleniumWeb浏览器或任何可以在Docker容器中运行的轻量级.一次性实例. 测试容器使以下类型的测试更加容易: 数据访问层集成测试: 使用MySQL,PostgreSQL或Oracle数据库的容器化实例测试您的数据访问层代码,但无需在开发人员的计算机上进行复杂的设置,并且测试将始终从已知的数据库状态开始,避免"垃圾"数据的干扰.也可以使用任何其他可以容器

  • Java使用自定义注解实现函数测试功能示例

    本文实例讲述了Java使用自定义注解实现函数测试功能.分享给大家供大家参考,具体如下: 一 自定义注解 使用@interface定义Annotation 使用Annotation修饰程序中的类.方法.变量.接口等定义,通常我们会把Annotation放在所有修饰符之前. 定义带成员变量的Annotation. 为Annotation的成员变量指定初始值. 二 提取Annotation Annotation接口来代表程序元素前面的注释,该接口是所有Annotation类型的父接口. Annotat

  • Java核心库实现AOP过程

    这篇文章是关于Java的一个疑难杂症,通过利用Java核心库实现简单的AOP方法,并把实例代码做了分析对照,以下是全部内容: Spring是一个十分火热开源框架,而AOP(面向切面编程)则是Spring最重要的概念之一,为了更好的理解和学习AOP的思想,使用核心库来实现一次不失为一个好方法. 首先介绍一下AOP的概念,AOP(Aspect Oriented Programming),即面向切面编程,所谓的面向切面编程,就是从一个横切面的角度去设计代码的思想,传统的OOP思想是用封装继承和多态构造

  • Java核心库实现简单的AOP

    Spring是一个十分火热开源框架,而AOP(面向切面编程)则是Spring最重要的概念之一,为了更好的理解和学习AOP的思想,使用核心库来实现一次不失为一个好方法. 首先介绍一下AOP的概念,AOP(Aspect Oriented Programming),即面向切面编程,所谓的面向切面编程,就是从一个横切面的角度去设计代码的思想,传统的OOP思想是用封装继承和多态构造一种纵向的层次关系,但不适合定义横向的关系,而AOP思想则对此进行了很好的补充. 例如日志管理代码往往横向的散布在很多对象层次

  • Java案例之随机验证码功能实现实例

    实现的功能比较简单,就是随机产生了四个字符然后输出.效果图如下,下面我会详细说一下实现这个功能用到了那些知识点,并且会把 这些知识点详细的介绍出来.哈哈 ,大神勿喷,对于初学Java的人帮助应该蛮大的.嘿嘿. 先上效果图: 源代码: RandomGen.java(实现产生验证码功能的类) package verificationcode; import java.util.Random; public class RandomGen { //生成四位不重复的验证码 public static S

  • Java Socket实现多线程通信功能示例

    本文实例讲述了Java Socket实现多线程通信功能的方法.分享给大家供大家参考,具体如下: 前面的文章<Java Socket实现单线程通信的方法示例>说到怎样写一个最简单的Java Socket通信,但是文章中的例子有一个问题就是Server只能接受一个Client请求,当第一个Client连接后就占据了这个位置,后续Client不能再继续连接,所以需要做些改动,当Server没接受到一个Client连接请求之后,都把处理流程放到一个独立的线程里去运行,然后等待下一个Client连接请求

  • JS基于myFocus库实现各种功能的tab选项卡切换效果

    本文实例讲述了JS基于myFocus库实现各种功能的tab选项卡切换效果.分享给大家供大家参考.具体如下: 这里介绍使用myFocus-tab实现各种功能的选项卡切换,有的是带有动画效果的,各款基于myFocus库制作的焦点图风格皮肤,可自行按需选择,myFocus焦点图库及皮肤可自由使用,保留作者相关信息即可,谢谢支持!^^ 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-myfocus-plug-tab-cha-nav-codes/ 具

  • Java使用jni清屏功能的实现(只针对cmd)

    JNI简介 JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了.使用java与本地已编译的代码交互,通常会丧失平台可移植性.但是,有些情况下这样做是可以接受的,甚至是必须的.例如,使用一些旧的库,

  • 使Java的JButton文字隐藏功能的实现(不隐藏按钮的前提)

    在网上虽然看到了方法,但是处理感觉很复杂,我的办法,老实说,是突然试一下试到的,哈哈QWQ OK,开始说明如何整的. 效果如上图所示 代码如下 package csdn.article; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class JButtonTextSize extends JFram

  • ASP.NET Core扩展库的相关功能介绍

    亲爱的.Neter们,在我们日复一日的编码过程中是不是会遇到一些让人烦恼的事情: 日志配置太过复杂,各种模板.参数也搞不清楚,每次都要去查看日志库的文档,还需要复制粘贴一些重复代码,好无赖 当需要类型转换时,使用AutoMapper时感觉配置又复杂,自己写人肉转换代码又冗长,又枯燥,好无聊 当调用其他服务时,总是不放心,于是在调用前.调用后总是不断重复地记录请求和应答日志? 当其他服务需要令牌时,我们不得不管理令牌的生命周期,而且不同第三方服务令牌的认证.维护过程还不一样,有时调用每一个接口时都

随机推荐