springboot单元测试技术

标签: spring boot spring java | 发表时间:2021-04-18 17:20 | 作者:qihaiyan
出处:http://springcamp.cn/

整个软件交付过程中,单元测试阶段是一个能够最早发现问题,并且可以重复回归问题的阶段,在单元测试阶段做的测试越充分,软件质量就越能得到保证。 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-unit-test

一、概述

一个功能的全链路测试,往往要依赖于很多外部组件,如数据库、redis、kafka、第三方接口等,单元测试的执行环境有可能受网络限制没有办法访问这些外部服务。因此,我们希望通过一些技术手段,能够用单元测试技术进行完整的功能测试,而不依赖于外部服务。

二、REST接口的测试

springboot提供了testRestTemplate工具用于在单元测试中测试接口,该工具只需指定接口的相对路径,不需要指定域名和端口。这个特性非常有用,因为springboot的单元测试运行环境的web服务是一个随机端口,是通过下面这个注解指定的:

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

以下是通过testRestTemplate测试我们开发的 /remote接口的方法:

        @Test
    public void testRemoteCallRest() {
        String resp = testRestTemplate.getForObject("/remote", String.class);
        System.out.println("remote result : " + resp);
        assertThat(resp, is("{\"code\": 200}"));
    }

三、第三方接口的依赖

上面的例子中,我们的remote接口会调用一个第三方接口 http://someservice/foo,我们的构建服务器中有可能受网络限制,无法访问这个第三方接口,就会导致单元测试无法执行。我们可以通过springboot提供的 MockRestServiceServer 工具来解决这个问题。

首先定义一个MockRestServiceServer变量

    private MockRestServiceServer mockRestServiceServer;

在单元测试的初始化阶段进行初始化

        @Before
    public void before() {
        mockRestServiceServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();

        this.mockRestServiceServer.expect(manyTimes(), MockRestRequestMatchers.requestTo(Matchers.startsWithIgnoringCase("http://someservice/foo")))
                .andRespond(withSuccess("{\"code\": 200}", MediaType.APPLICATION_JSON));

    }

这样,当我们的单元测试程序中调用 http://someservice/foo接口时,就会固定返回 {"code": 200}这个返回值,而不是真正的去访问这个第三方接口。

四、数据库的依赖

数据库的依赖比较简单,直接使用h2这个嵌入式数据库就可以,所有的数据库操作都是在h2这个嵌入式数据库中执行的。

已gradle配置为例:

    testImplementation 'com.h2database:h2'

单元测试配置文件中的数据库连接使用h2:

    spring:
  data:
    url: jdbc:h2:mem:ut;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:

这样,当我们的单元测试程序中调用 http://someservice/foo接口时,就会固定返回 {"code": 200}这个返回值,而不是真正的去访问这个第三方接口。

五、redis的依赖

网上有一个开源的redis mockserver,模仿了大部分的redis指令,我们只需要引入这个redis-mockserver即可。 最初版本是一个国人开发的,示例中引入的是老外fork的一个版本,补充了一些指令,但是找不到源码了,我又fork了一个版本,补充了setex、zscore两个指令,有需要的可以自己编译。 代码连接 https://github.com/qihaiyan/redis-mock

已gradle配置为例:

    testImplementation 'com.github.fppt:jedis-mock:0.1.16'

单元测试配置文件中的数据库连接使用redis mockserver:

    spring:
  redis:
    port: 10033

增加一个单独的redis配置文件,用于在单元测试中启动redis mockserver:

    @TestConfiguration
public class TestRedisConfiguration {

    private final RedisServer redisServer;

    public TestRedisConfiguration(@Value("${spring.redis.port}") final int redisPort) throws IOException {
        redisServer = RedisServer.newRedisServer(redisPort);
    }

    @PostConstruct
    public void postConstruct() throws IOException {
        redisServer.start();
    }

    @PreDestroy
    public void preDestroy() {
        redisServer.stop();
    }
}

六、kafka的依赖

spring提供了一个kafka的测试组件,可以在单元测试期间启动一个嵌入式的kafka服务EmbeddedKafka,模拟真实的kafka操作。

已gradle配置为例:

    testImplementation "org.springframework.kafka:spring-kafka-test"

通过ClassRule初始化EmbeddedKafka,有两个topic: testEmbeddedIn 和 testEmbeddedOut 。

        private static final String INPUT_TOPIC = "testEmbeddedIn";
    private static final String OUTPUT_TOPIC = "testEmbeddedOut";
    private static final String GROUP_NAME = "embeddedKafkaApplication";

    @ClassRule
    public static EmbeddedKafkaRule embeddedKafkaRule = new EmbeddedKafkaRule(1, true, INPUT_TOPIC, OUTPUT_TOPIC);

    public static EmbeddedKafkaBroker embeddedKafka = embeddedKafkaRule.getEmbeddedKafka();

    private static KafkaTemplate<String, String> kafkaTemplate;

    private static Consumer<String, String> consumer;

    @BeforeClass
    public static void setup() {

        Map<String, Object> senderProps = KafkaTestUtils.producerProps(embeddedKafka);
        DefaultKafkaProducerFactory<String, String> pf = new DefaultKafkaProducerFactory<>(senderProps);
        kafkaTemplate = new KafkaTemplate<>(pf, true);

        Map<String, Object> consumerProps = KafkaTestUtils.consumerProps(GROUP_NAME, "false", embeddedKafka);
        DefaultKafkaConsumerFactory<String, String> cf = new DefaultKafkaConsumerFactory<>(consumerProps);
        consumer = cf.createConsumer();
        embeddedKafka.consumeFromAnEmbeddedTopic(consumer, OUTPUT_TOPIC);
    }

在单元测试程序的配置文件中,可以指定这2个kafka的topic

    cloud.stream.bindings:
    handle-out-0.destination: testEmbeddedOut
    handle-in-0.destination: testEmbeddedIn
    handle-in-0.group: embeddedKafkaApplication

相关 [springboot 单元测试 技术] 推荐:

springboot单元测试技术

- - 海思
整个软件交付过程中,单元测试阶段是一个能够最早发现问题,并且可以重复回归问题的阶段,在单元测试阶段做的测试越充分,软件质量就越能得到保证. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-unit-test.

用JWT技术为SpringBoot的API增加授权保护 – springcamp

- -
示例 https://github.com/qihaiyan/jwt-boot-auth. 用spring-boot开发RESTful API非常的方便,在生产环境中,对发布的API增加授权保护是非常必要的. 现在我们来看如何利用JWT技术为API增加授权保护,保证只有获得授权的用户才能够访问API.

Android单元测试

- - CSDN博客推荐文章
    单元测试不管对于初学编程还是已经工作了很久的开发者来说,都不乐意花时间去写认为没用的代码进行测试,只要交给测试人员就行了,虽然这样也能把软件改出来,但也许你要花上几倍的时间去修改问题,如果在开发的过程中花点时间去写单元测试代码,把尽可能出问题的地方都测试一遍,把问题扼杀在最开始的地方,这样你就不必为后来找问题出处而烦恼.

Hadoop之MapReduce单元测试

- - ITeye博客
通常情况下,我们需要用小数据集来单元测试我们写好的map函数和reduce函数. 而一般我们可以使用Mockito框架来模拟OutputCollector对象(Hadoop版本号小于0.20.0)和Context对象(大于等于0.20.0). 下面是一个简单的WordCount例子:(使用的是新API).

SpringBoot的事务管理

- - ImportNew
Springboot内部提供的事务管理器是根据autoconfigure来进行决定的. 比如当使用jpa的时候,也就是pom中加入了spring-boot-starter-data-jpa这个starter之后(之前我们分析过 springboot的自动化配置原理). Springboot会构造一个JpaTransactionManager这个事务管理器.

springboot aop日志记录

- - 编程语言 - ITeye博客
一、POM增加AOP JAR包. 三、SysAspect类. 注:@annotation(cn.com.hfai.controller.system.Logweb) 一定要指定Logweb类. 四、在Controller类的方法之上加上注解 @Logweb 即可. 注:这个只是打印在控制台上,若想放到数据库中,则需要增加操作数据库的业务代码.

K8S部署SpringBoot应用_都超的博客-CSDN博客_k8s springboot

- -
K8S环境机器做部署用,推荐一主双从. Docker Harbor私有仓库,准备完成后在需要使用仓库的机器docker login. 开发机器需要Docker环境,build及push使用. 一、构建基本Springboot工程,本例所用版本及结构如下图. 创建测试代码,简单打印几行log. .

“单元测试要做多细?”

- - 酷壳 - CoolShell.cn
这篇文章主要来源是StackOverflow上的一个回答——“ How deep are your unit tests?”. 一个有13.8K的分的人( John Nolan)问了个关于TDD的问题,他说——. “TDD需要花时间写测试,而我们一般多少会写一些代码,而第一个测试是测试我的构造函数有没有把这个类的变量都设置对了,这会不会太过分了.

文章: Android中的单元测试

- - InfoQ cn
随着Agile的普及,以及开发人员对测试重要性的认识逐步加深,单元测试已经成了越来越多软件项目开发中不可缺少的一部分. 无论项目是不是采用TDD的形式来进行开发,单元测试都能够为项目的修改和重构提供一定的保障. 有奖参与:天翼伦敦会,上传应用,为中国队加油. QClub七月技术沙龙(太原/北京/上海/厦门/西安 7月21/28/29日 免费报名中.

迈出单元测试的第一步

- - 酷勤网-挖经验 [expanded by feedex.net]
单元测试不仅是软件行业的最佳实践,在敏捷方法的推动下,它也成为了可持续软件生产的支柱. 年度敏捷调查,70%的参与者会对他们的代码进行单元测试. 单元测试和其他敏捷实践密切相关,所以开始编写测试是组织向敏捷转型的踏脚石. 我将在本文介绍符合要求的小技巧,以及在开发周期里进行单元测试的步骤. 没有自动化,单元测试的习惯也不会持续太久.