单元测试1@SpringBootTest


前言

随着软件行业的蓬勃发展,完成编码工作后,单元测试必不可少,但是单元测试的目的与作用还有何时如何写单元测试,这些你都知道吗?

一、单元测试是什么?

  1. 维基百科中是这样描述的:
    单元测试又称为模块测试,是针对程序模块(软件设计中的最小单元)来进行正确性检验的测试工作。
  2. 作用:
    (1)可以减少代码bug数
    (2)提高代码可读性,提高代码质量
    (3)能更加理解代码逻辑设计,减少逻辑错误
  3. 何时写单元测试:
    (1)跟随团队风格
    (2)一般先写完一个功能或者一个service,一个接口就写单元测试。如果是TDD风格,那就先写测试吧

二、如何写单元测试

在单元测试框架还没有出现的年代,我们一般要测试一段代码直接写个main方法就可以了,但是如果有多个,那就很不方便了
1.现在的项目一般是springboot项目,就为大家讲解下springboot项目如何写单元测试,废话不多说,先上代码
代码如下(示例):

import com.example.entity.User;
import com.example.service.UserService;
import org.junit.*;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.*;

@SpringBootTest
@RunWith(SpringRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UserServiceTest0 {
    @Autowired
    private UserService userService;
    private static User user;

    @BeforeClass
    public static void beforeClass() {
        user = new User();
        user.setId( 1 );
        user.setUsername( "令狐冲" );
        user.setPassword( "123" );
        System.out.println( "这是@BeforeClass方法" );
    }

    @Before
    public void before() throws Exception {
        System.out.println( "这是@Before方法" );
    }

    @Test
    public void test1InsertUser() {
        int i = userService.insertUser( user );
        assertThat( i, is( 1 ) );
    }

    @Test
    public void test4DeleteById() {
        int i = userService.deleteUser( 1 );
        assertThat( i, is( 1 ) );
    }

    @Test
    public void test3Update() {
        int i = userService.updateUser( user );
        assertThat( i, is( 1 ) );
    }

    @Test(timeout = 1000000)
    public void test2SelectById() {
        User userBySearch = userService.selectById( 1 );
        assertEquals( user, userBySearch );

        assertNotNull( userBySearch );

        assertNotSame( user, userBySearch );

        assertTrue( "这两个user相等", user.equals( userBySearch ) );

        assertThat( userBySearch.getUsername(), containsString( "冲" ) );

        if (userBySearch==null) {
            fail( "查询失败" );
        }
    }

    @Ignore
    @Test(expected = NumberFormatException.class)
    public void getUserById0() {
        System.out.println( userService.selectById( Integer.valueOf( "a" ) ) );
    }


    @After
    public void after() throws Exception {
        System.out.println( "这是@After方法" );
    }

    @AfterClass
    public static void afterClass() throws Exception {
        System.out.println( "这是@AfterClass方法" );
    }

}

需要导入的依赖
spring-boot-starter-test,导入后下面这些类库将被一同依赖进去:
JUnit
Spring Test & Spring Boot Test
AssertJ
Hamcrest
Mockito

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
 

在这里讲解下各个注解的作用及流程
1).@SpringBootTest
基本等同于启动了整个服务,此时便可以开始功能测试。
属性值:classes,webEnvironment

@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)

(1)classes 指定配置文件,一般不写。默认去找application.yml中指定的配置文件,替代@ContextConfiguration(locations={“classpath:applicationContext.xml”}的用法
(2)webEnvironment 有4个属性值,大家看需求选择,如果只是做功能测试,直接写@SpringBootTest即可,4个属性值分别是:
mock:此值为默认值,该类型提供一个mock环境,时内嵌的服务(servlet容器)并没有真正启动,也不会监听web服务端口。
RANDOM_PORT:启动一个真实的web服务,监听一个随机端口
DEFINED_PORT:启动一个真实的web服务,监听一个定义好的端口
NONE:启动一个非web的ApplicationContext,既不提供mock环境,也不 提供真实的web服务

2.Junit中的常用注释
1)@BeforeClass 全局只会执行一次,而且是第一个运行
2)@Before 在测试每一个具体方法运行之前运行
3)@Test 测试具体方法
expected属性
timeout属性
4)@After 在测试每一个具体方法运行之后=运行
5)@AfterClass 全局只会执行一次,而且是最后一个运行
6)@Ignore 忽略此方法
3.运行器指定@RunWith
1)@RunWith(JUnit4.class)就是指用JUnit4来运行
2)@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境,一般使用@RunWith(SpringRunner.class)
3.@RunWith(Suite.class)的话就是一套测试集合

@RunWith( Suite.class )
@Suite.SuiteClasses( {UserServiceTest.class,MockTest.class} )

4.@RunWith(Parameterized.class) 参数化运行器,配合@Parameters使用junit的参数化功能

5.Mockito
(1)使用场景:测试对象依赖很多,难以模拟或者模拟不出来;所依赖的功能还没有写完
(2)上代码:

@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UserServiceTest1 {
    @MockBean
    private UserService userService;
    private User user = mock(User.class);

    @BeforeClass
    public static void beforeClass() {
        System.out.println( "这是@BeforeClass方法" );
    }

    @Before
    public void before() throws Exception {
        System.out.println( "这是@Before方法" );
    }

    @Test
    public void test1InsertUser() {
        int i = userService.insertUser( user );
        assertThat( i, is( 1 ) );
    }

    @Test
    public void test1InsertUserTest() {
        int a = 0;
        User mock = mock( User.class );
        int i = userService.insertUser( mock );
    }

    @Test
    public void test1InsertUserTest1() {
        when( userService.insertUser( user ) ).thenReturn( 1 );
        int i = userService.insertUser( user );
        assertThat( i, is( 1 ) );
    }

    @Test
    public void test1InsertUserTest2() {
        doReturn( 1 ).when( userService ).insertUser( user );
        int i = userService.insertUser( user );
        assertThat( i, is( 1 ) );
        verify(userService).insertUser(user);
    }

    @Test
    public void test4DeleteById() {
        int i = userService.deleteUser( 1 );
        assertThat( i, is( 1 ) );
    }

    @Test
    public void test3Update() {
        int i = userService.updateUser( user );
        assertThat( i, is( 1 ) );
    }

    @Test(timeout = 1000000)
    public void test2SelectById() {
        User userBySearch = userService.selectById( 1 );
        assertEquals( user, userBySearch );

        assertNotNull( userBySearch );

        assertNotSame( user, userBySearch );

        assertTrue( "这两个user相等", user.equals( userBySearch ) );

        assertThat( userBySearch.getUsername(), containsString( "冲" ) );

        if (userBySearch==null) {
            fail( "查询失败" );
        }
    }

    @Ignore
    @Test(expected = NumberFormatException.class)
    public void getUserById0() {
        System.out.println( userService.selectById( Integer.valueOf( "a" ) ) );
    }


    @After
    public void after() throws Exception {
        System.out.println( "这是@After方法" );
    }

    @AfterClass
    public static void afterClass() throws Exception {
        System.out.println( "这是@AfterClass方法" );
    } 
}

总结

今天就分享到这里,下次为大家介绍断言与mockito的打桩

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值