单元测试-学习笔记

前言

关于单元测试的内容暂时也是在学习中,记录一下单元测试的用法,提供参考,只提供了些核心代码。

一、涉及的依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

二、注解说明和案例演示

标识说明
@BeforeAll@BeforeAll 带注释的方法必须是测试类中的静态方法。在执行@Test之前会优先执行这个方法,并且只执行一次
@BeforeEach@BeforeEach 带注释的方法不能是静态方法,否则会抛出运行时错误。在执行@Test之前会优先执行这个方法并且每次执行都会执行@BeforeEach修饰的方法
@MockBean模拟一个Bean,是个壳子Bean,其行为和返回值可以用 Mockito.when(XXX).then(XXX)进行预设模拟
@DisplayName()执行时右侧名称展示,具体后面有图标明,可以配合@RepeatedTest()注解使用
@RepeatedTest(5)重复执行5次

样例``

package com.example.unit.test.demo.service.impl;

import com.example.unit.test.demo.api.OtherService;
import com.example.unit.test.demo.controller.domain.Calculator;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

/**
 * @author 起凤
 * @description: TODO
 * @date 2022/7/6
 */
@Slf4j
@SpringBootTest
public class BeforeEachTest {

    @MockBean
    private OtherService otherService;

    // BeforeAll 每个方法执行时,repeated时只会调用一次
    @BeforeAll
    public static void init() {
        log.warn("BeforeAll Method init() method called");
    }

    // BeforeEach 每个方法执行时,repeated时只会调用多次
    @BeforeEach
    public void initEach() {
        log.error("BeforeEach initEach() method called");
    }

   // DisplayName 执行时展示板上加个别名,看图
    @DisplayName("Add operation test")
    @RepeatedTest(5)
    void addNumber(TestInfo testInfo, RepetitionInfo repetitionInfo) {
        System.out.println("Running Test  ->" + repetitionInfo.getCurrentRepetition());
        Assertions.assertEquals(2, Calculator.add(1, 1), "1 + 1 should equal 2");
    }

}

执行时能看到 @BeforeAll 最早执行,且只执行一次, @BeforeEach每次重复都执行且先于重复体执行,@RepeatedTest(5) 标识后会执行5次,@DisplayName("Add operation test") 标识后重复执行里的左侧绿色的勾勾下的名称就叫Add operation test

在这里插入图片描述

样例DemoServiceTest.java

package com.example.unit.test.demo.service.impl;

import com.example.unit.test.demo.api.OtherService;
import com.example.unit.test.demo.controller.domain.EchoRequest;
import com.example.unit.test.demo.controller.domain.EchoResponse;
import com.example.unit.test.demo.service.IDemoService;
import com.example.unit.test.demo.utils.SessionUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

import java.util.UUID;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author 起凤
 * @description: TODO
 * @date 2022/7/6
 */
@SpringBootTest
class DemoServiceTest {

    // 模拟外部调用需要进行Mock
    @MockBean
    private SessionUtils sessionUtils;
    @MockBean
    private OtherService otherService;
    @Autowired
    private IDemoService demoService;

    // @BeforeAll 带注释的方法必须是测试类中的静态方法。
    // 在执行@Test之前会优先执行这个方法
    @BeforeAll
    public static void beforeAll() {
        System.out.println("BeforeAll init() method called");
    }

    // @BeforeEach 带注释的方法不能是静态方法,否则会抛出运行时错误。
    // 对外请求和线程上下文相关行为进行Mock
    @BeforeEach
    public void beforeEach() {
        // 进行提前mock 相当于当 sessionUtils.getCurrentUser() 被调用时就会返回 hello
        Mockito.when(sessionUtils.getCurrentUser()).thenReturn("hello");
        // 进行提前mock 相当于当 otherService.doSomething() 被调用时就会返回该入参时候的第0个参数
        // 可以 Mockito.anyXXXX, 具体进入看源码,对请求入参的参数mock
        Mockito.when(otherService.doSomething(Mockito.anyString()))
                .thenAnswer((Answer<String>) invocationOnMock -> invocationOnMock.getArgument(0));
    }

    // 使用随机输入测试 Echo,这里demoService的echo方法内部有调用 OtherService的doSomething方法
    // OtherService 已经被@MockBean修饰,且该方法提前在@BeforeEache里预设mock调用是是返回第一个入参
    @Test
    public void testEchoWithRandomInput() {
        String input = UUID.randomUUID().toString();
        EchoResponse resp = demoService.echo(EchoRequest.builder()
                .input(input).build());

        // 这里 resp.getOutput() == input正常不会抛出异常
        Assertions.assertEquals(resp.getOutput(), input);
        // 这里不一致会抛异常 resp.getOutput() 返回的是input 是一个UUID值
        Assertions.assertEquals(resp.getOutput(), "1234");

    }

    @Test
    void testSessionUtils() {
        String currentUser = sessionUtils.getCurrentUser();
        /// 下面这行打开会报错 前面设置了 sessionUtils调用getCurrentUser时返回 hello
        // Assertions.assertEquals(currentUser,"hello1");
        Assertions.assertEquals(currentUser, "hello");

        String aaa = otherService.doSomething("aaa");
        Assertions.assertEquals(aaa, "aaa1");
    }
}

样例 IDemoService.java

package com.example.unit.test.demo.service.impl;

import com.example.unit.test.demo.api.OtherService;
import com.example.unit.test.demo.controller.domain.EchoRequest;
import com.example.unit.test.demo.controller.domain.EchoResponse;
import com.example.unit.test.demo.service.IDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 起凤
 * @description: TODO
 * @date 2022/7/6
 */
@Component
public class DemoService implements IDemoService {

    @Autowired
    private OtherService otherService;

    @Override
    public EchoResponse echo(EchoRequest request) {
        return EchoResponse.builder()
                .output(otherService.doSomething(request.getInput()))
                .build();
    }
}

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值