单元测试—JUnit5浅析

目录

介绍: 

   常用注解:

断言:

前置条件(assumptions)

 嵌套测试

参数化测试:


介绍: 

JUnit5=JUnit platform(测试框架基础)+JUnit Jupiter(新版本的,包含测试引擎)+JUnit Vintage(老版本的编程模型)

JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。

JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部 包含了一个测试引擎,用于在Junit Platform上运行。

JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。

 如果你需要用JUnit4的话需要导入以下依赖:

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

以前:@SpringBootTest+@RunWith(SpringTest.class)

现在: 编写测试方法我们用@Test即可,如果需要Spring功能,@SpringBootTest,可以使用@AutoWired,@Transactional...

   常用注解:

    @Test:表示方法为测试方法,职责单一;

    @ParameterizedTest:表示为参数化测试

    @DisplayName:为测试方法或者类设置展示名称

    @BeforeEach:每个单元测试之前执行

    @Diabled:表示该测试方法不执行

    @Timeout:表示测试方法运行超过指定时间就会返回错误

    @ExtendWith:为测试扩展引用


@Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    DataSource dataSource;

    @Autowired
    UserMapper userMapper;


    @Autowired
    StringRedisTemplate redisTemplate;


    @Autowired
    RedisConnectionFactory redisConnectionFactory;


    @Test
    void contextLoads() {

//        jdbcTemplate.queryForObject("select * from account_tbl")
//        jdbcTemplate.queryForList("select * from account_tbl",)
        Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
        log.info("记录总数:{}", aLong);

        log.info("数据源类型:{}", dataSource.getClass());

    }

断言:

简而言之就是对测试进行条件判断:检查业务逻辑返回的数据是否合理;测试结束后,会有测试报告;

方法

说明

assertEquals

判断两个对象或两个原始类型是否相等

assertNotEquals

判断两个对象或两个原始类型是否不相等

assertSame

判断两个对象引用是否指向同一个对象

assertNotSame

判断两个对象引用是否指向不同的对象

assertTrue

判断给定的布尔值是否为 true

assertFalse

判断给定的布尔值是否为 false

assertNull

判断给定的对象引用是否为 null

assertNotNull

判断给定的对象引用是否不为 null

package com.atguigu.admin;

import org.aspectj.lang.annotation.After;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.TimeUnit;

/**
 * @author diao 2022/2/8
 */
/*
 * @SpringBootTest中包含了@BootStrapWith与@ExtendWith:作用就是以spring的方式去驱动测试
 * 所以每次开启时要启动容器
 * */
@SpringBootTest
public class tt {
    //在所有测试前执行
    @BeforeAll
    void testBeforeAll() {
        System.out.println("我才是最先执行的");
    }

    /*测试前置条件:与断言assert大致相同,不过它失败了不会抛出异常
    只会导致下面的测试不会进行
    * */
    @DisplayName("测试前置条件")
    @Test
    void testassumptions() {
        Assumptions.assumeTrue(true, "结果不是true");
        //只有前置条件为true,后面的才会响应
        System.out.println("111111");
    }

    @DisplayName("测试前置条件2")
    @Test
    void testassumptions2() {
        Assumptions.assumeFalse(true, "结果不是false");
//        因为前面前置条件不满足false,所以下面的不进行
        System.out.println("111111");
    }

    /*嵌套测试:更加有层次感
    *
    * */



    //    断言机制,前面断言失败那么后面的都不会执行
    @DisplayName("测试断言机制")
    @Test
    void testSimpleAssertions() {
        int cal = cal(3, 3);
        //进行断言,判断
        Object obj1 = new Object();
        Object obj2 = new Object();
//      assertSame(obj1,obj2);
    }


    int cal(int a, int b) {
        int num = a + b;
        return num;
    }


    @DisplayName("测试displayname注解")
    @Test
    void testDisplayName() {
        System.out.println(1);
    }

    @DisplayName("测试2")
    @Test
    void testDisplayName2() {
        System.out.println(2);
    }

    @Timeout(value = 500, unit = TimeUnit.SECONDS)//500ms则超时
    @Test
    void TestTimeOut() throws InterruptedException {
        //因为超过500ms就会抛出异常,我们这里sleep400ms
        Thread.sleep(400);
    }

    /*@RepeatedTest():重复测试
     * */
    @RepeatedTest(5)
    @Test
    void test3() {
        System.out.println("重复测试中...");
    }


    //    在每一个单元测试之前执行
    @BeforeEach
    void testBeforeEach() {
        System.out.println("测试马上开始");
    }

    //    在每一个单元测试之后执行
    @AfterEach
    void testAfterEach() {
        System.out.println("测试结束了...");
    }

    //    在所有测试之后执行
    @AfterAll
    void TestAfterAll() {
        System.out.println("我是最后一个执行的...");
    }

}

前置条件(assumptions)

 类似于断言,但是区别在于它判断失败不会因此抛出异常,assumptions只会让测试方法执行终止;

@DisplayName("前置条件")
public class AssumptionsTest {
 private final String environment = "DEV";
 
 @Test
 @DisplayName("simple")
 public void simpleAssume() {
    assumeTrue(Objects.equals(this.environment, "DEV"));
    assumeFalse(() -> Objects.equals(this.environment, "PROD"));
 }
 
 @Test
 @DisplayName("assume then do")
 public void assumeThenDo() {
    assumingThat(
       Objects.equals(this.environment, "DEV"),
       () -> System.out.println("In DEV") //如果前置失败则不会打印这个
    );
 }
}

 嵌套测试

   主要是通过内部类和@Nested注解实现嵌套测试


    @Nested//嵌套测试的注解
    @DisplayName("when new")
    class WhenNew{
        
        @BeforeEach//在每一个单元测试之前创建一个新的栈
        void createNewStack(){
            stack=new Stack<>();
        }
        
        @Test
        @DisplayName("is empty")
        void isEmpty(){
            //进行断言,测试栈是不是为空,空就ok
            assertTrue(stack.isEmpty());
        }
        
        /*assertThrows
        *断言判断异常,如果用到了数据结构,对数据结构进行操作后再进行判断的话
        * Stack::操作->assertThrows(异常.class,Stack::操作)
        * */
        @Test 
        @DisplayName("throws EmptyStackException when popped")
        void throwExceptionOfPopped(){//抛出异常,如果stack pop后为空
            assertThrows(EmptyStackException.class,stack::pop);
        }
        
        @Test
        @DisplayName("throws EmptyStackException when peeked")
        void throwsExceptionWhenPeekded(){
            assertThrows(EmptyStackException.class,stack::peek);
        }
        
        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing{
            String element="an Element";

            @BeforeEach
            void pushElement(){
                stack.push(element);
            }
            
            @Test
            @DisplayName("judage empty")
            void isNotEmpty(){
                assertFalse(stack.isEmpty());
            }
            
            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementPopped(){
                //断言判断stack pop()出来的元素是否和element相等
                assertEquals(element,stack.pop());
                assertFalse(stack.isEmpty());
            }
            
            @Test
            @DisplayName("ElementOfPeekIsEmpty")
            void returnElementPeeked(){
                assertEquals(element,stack.peek());
                assertFalse(stack.isEmpty());
            }
        }
        
       
        
    }
    
}

参数化测试:

 好处:不需要每次加一个参数就新增一个单元测试,减少了代码冗余; 

@ValueSource:八大基础类型+String+Class类型;

@NullSource:为参数化测试提供一个null的入参;

@EnumSource:为参数化入参提供一个枚举入参;

@MethodSource:方法返回值作为测试的入参参数(方法的返回需要是一个流);

@CsvFileSource:CSV内容作为参数...;


    @ParameterizedTest
    @DisplayName("单元测试")
    @ValueSource(ints = {1,2,3,4,5}) //可以放八大类型
    void testParameterizedTest(int i){
        System.out.println(i);
    }

    @ParameterizedTest
    @DisplayName("参数测试")
    @MethodSource("stringProvider")
    void testParameterized2(String i){
        System.out.println(i);
    }
    
    static Stream<String> stringProvider() {
      return  Stream.of("apple", "banana", "atguigu");
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fairy要carry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值