mockito加junit搞定单元测试-cnblog

发布时间 2023-12-22 08:00:28作者: 起跑线小言

转自:mockito加junit搞定单元测试

https://www.bilibili.com/video/BV1P14y1k7Hi?p=1&vd_source=a3ca5632ce12ee8045822c508dc81551

其他好文推荐:

1、2023单元测试利器Mockito框架详解(超详细~)

https://blog.csdn.net/m0_58026506/article/details/131423775

2、一文让你快速上手 Mockito 单元测试框架!https://zhuanlan.zhihu.com/p/386179879

3、【测试相关】Java Mock框架之Mockito https://www.jianshu.com/p/667bffb8b869

一、简介

1702988529924

二.mockito的单独使用

2.1 mock对象与spy对象

1702988832383

ps: 上面2.2表中表示junit5和4的初始化注解不一样地方,后面我们所讲的就以junit5来讲了。

2.2.1. Mockito与JUnit5的集成

参考:https://www.baeldung.com/mockito-junit-5-extension

除了Mockito本身的jar以及JUnit5本身的jar外,还需要依赖:mockito-junit-jupiter,简单起见,可直接引入Spring Boot的test,它已经帮我们解决了依赖问题,并且天然的支持Mockito和JUnit5(需要Spring Boot 2.4.0+,否则支持的是JUnit4):

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

或者使用如下依赖
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>

1702990709197

2.2.2 代码演示:

方式一:通过@ExtendWith(MockitoExtension.class) + @Mock等注解

1702991929872

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;


@ExtendWith(MockitoExtension.class)
class MemberServiceImplTest {

    @Mock
    private MemberLevelDao mockMemberLevelDao;
    @Spy
    private MemberLevelDao spyMockMemberLevelDao;


    @Test
    void testMock1() {
        // 判断某对象是不是mock对象 true
        System.out.println("Mockito.mockingDetails(mockMemberLevelDao).isMock() = " + Mockito.mockingDetails(mockMemberLevelDao).isMock());
        // false
        System.out.println("Mockito.mockingDetails(mockMemberLevelDao).isSpy() = " + Mockito.mockingDetails(mockMemberLevelDao).isSpy());
        // ture mock对象包含spy对象,spy对象的mock对象的一种特殊的情况
        System.out.println("Mockito.mockingDetails(spyMockMemberLevelDao).isMock() = " + Mockito.mockingDetails(spyMockMemberLevelDao).isMock());
        // true
        System.out.println("Mockito.mockingDetails(spyMockMemberLevelDao).isSpy() = " + Mockito.mockingDetails(spyMockMemberLevelDao).isSpy());
    }
}

打印结果:

Mockito.mockingDetails(mockMemberLevelDao).isMock() = true
Mockito.mockingDetails(mockMemberLevelDao).isSpy() = false
Mockito.mockingDetails(spyMockMemberLevelDao).isMock() = true
Mockito.mockingDetails(spyMockMemberLevelDao).isSpy() = true

方式二:通过Mockito.mock(xxx.class)等方法

1702992605888

@ExtendWith(MockitoExtension.class)
class MemberServiceImplTest {

    private MemberLevelDao mockMemberLevelDao;
    private MemberLevelDao spyMockMemberLevelDao;
    @InjectMocks
    private MemberServiceImpl memberServiceImplUnderTest;

    @BeforeEach
    void setUp() {
        mockMemberLevelDao = Mockito.mock(MemberLevelDao.class);
        spyMockMemberLevelDao = Mockito.spy(MemberLevelDao.class);
    }

    @Test
    void testMock1() {
        // 判断某对象是不是mock对象 true
        System.out.println("Mockito.mockingDetails(mockMemberLevelDao).isMock() = " + Mockito.mockingDetails(mockMemberLevelDao).isMock());
        // false
        System.out.println("Mockito.mockingDetails(mockMemberLevelDao).isSpy() = " + Mockito.mockingDetails(mockMemberLevelDao).isSpy());
        // ture mock对象包含spy对象,spy对象的mock对象的一种特殊的情况
        System.out.println("Mockito.mockingDetails(spyMockMemberLevelDao).isMock() = " + Mockito.mockingDetails(spyMockMemberLevelDao).isMock());
        // true
        System.out.println("Mockito.mockingDetails(spyMockMemberLevelDao).isSpy() = " + Mockito.mockingDetails(spyMockMemberLevelDao).isSpy());
    }
}

打印结果:(同上)

Mockito.mockingDetails(mockMemberLevelDao).isMock() = true
Mockito.mockingDetails(mockMemberLevelDao).isSpy() = false
Mockito.mockingDetails(spyMockMemberLevelDao).isMock() = true
Mockito.mockingDetails(spyMockMemberLevelDao).isSpy() = true

方式二:通过 initMocks(this);或 MockitoAnnotations.initMocks(this); 或MockitoAnnotations.openMocks(this);等方法来给本类(MemberServiceImplTest)中属性上面加了@Mock、@Spy等注解的属性创建mock对象,并赋值给这些属性/field

@ExtendWith(MockitoExtension.class)
class MemberServiceImplTest {

    @Mock
    private MemberLevelDao mockMemberLevelDao;
    @Spy
    private MemberLevelDao spyMockMemberLevelDao;
    @InjectMocks
    private MemberServiceImpl memberServiceImplUnderTest;

    @BeforeEach
    void setUp() {
        initMocks(this);
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testMock1() {
        // 判断某对象是不是mock对象 true
        System.out.println("Mockito.mockingDetails(mockMemberLevelDao).isMock() = " + Mockito.mockingDetails(mockMemberLevelDao).isMock());
        // false
        System.out.println("Mockito.mockingDetails(mockMemberLevelDao).isSpy() = " + Mockito.mockingDetails(mockMemberLevelDao).isSpy());
        // ture mock对象包含spy对象,spy对象的mock对象的一种特殊的情况
        System.out.println("Mockito.mockingDetails(spyMockMemberLevelDao).isMock() = " + Mockito.mockingDetails(spyMockMemberLevelDao).isMock());
        // true
        System.out.println("Mockito.mockingDetails(spyMockMemberLevelDao).isSpy() = " + Mockito.mockingDetails(spyMockMemberLevelDao).isSpy());
    }

2.3 参数匹配

参数匹配: 通过方法签名(参数)来指定哪些方法调用需要被处理(插桩、verify验证)

    @Test
    void testMock2() {
       // 拦截指定类型的对象参数
        Mockito.doReturn(new MemberLevelEntity()).when(mockMemberLevelDao).getGrowthPoint(ArgumentMatchers.any(String.class));//String.class 可以是自定义类型
    }

1702993853496

2.4 方法插桩

插桩: 指定调用某个方法时的行为(stubbing),达到相互隔离的目的

1702994043718

插桩的用处:
  • 返回指定值

  • 插桩的两种方式

    • when(obj.someMethod()).thenXxx():其中obj可以是mock对象
    • doXxx().when(obj).someMethod():其中obj可以是mock/spy对象(没返回值的打桩常用,如果void和异常)
  • 多次插桩

    • @Test
      void testMock2() {     
          when(mockMemberLevelDao.getGrowthPoint(any()))
          	.thenReturn(1).thenReturn(2).thenReturn(3);
          // 上面的方式也可以简写为:
          when(mockMemberLevelDao.getGrowthPoint(any())).thenReturn(1,2,3);
          // 断言getGrowthPoint()方法调用了几次
          Assertions.assertEquals(1, 3);
          Assertions.assertEquals(2, 3);
          Assertions.assertEquals(3, 3);
      }
      
  • thenAnswer 返回指定的逻辑

    • 1702995417029
  • 抛出异常

    • doThrow(RuntimeException.class).when(mockMemberLevelDao).getGrowthPoint(any());
      
  • 执行真正的原始方法

  • verify的使用

1702995897970

  • void返回值方法插桩

1702994131404

两种插桩方式的区别:

【mockito加junit搞定单元测试】 https://www.bilibili.com/video/BV1P14y1k7Hi/?p=7&share_source=copy_web&vd_source=55f99462ec0c8405d00e6ebecca29a3a

1702994267232

1702994204252

1702994711940