详解Mocktito单元测试

        什么是单元测试?在维基百科中给出的答案是:在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

通常来说,程序员每修改一次程序就会进行最少一次单元测试,在编写程序的过程中前后很可能要进行多次单元测试,以证实程序达到软件规格书要求的工作目标,没有程序错误;虽然单元测试不是必须的,但也不坏,这牵涉到项目管理的政策决定。

单元测试的目标是隔离程序部件并证明这些单个部件是正确的。一个单元测试提供了代码片断需要满足的严密的书面规约。因此,单元测试带来了一些益处。 单元测试在软件开发过程的早期就能发现问题。

常见的单元测试有JUNIT/JUNIT5、AssertJ、Mocktito等,本文主要介绍使用Mocktito做单元测试工具的常用方法

1、Mockito引用的jar包依赖
             <dependency>
                    <groupId>org.mockito</groupId>
                   <artifactId>mockito-core</artifactId>
                   <version>3.4.6</version>
                   <scope>test</scope>
             </dependency>

2、Mockito官方地址如下:https://site.mockito.org/

文档详细说明地址如下:https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html

3、常见命令简介

 (1)、@Mock()来创建和注入模拟实例
        (2)、@Spy()注释监视现有实例
        (3)、@InjectMocks()将模拟字段自动注入到测试对象中,Mockito不支持将模拟注入@Spy程序, 并且以下测试会导致异常,如果我们想让他们俩结合,就需要改造一下,通过构造函数的方法注入
        (4)、Verify方法用于检查是否发生了某些行为,使用InOrder可以验证方法的调用顺序
        (5)、使用 stubbing 存根模拟连续的调用
        (6)、参数匹配,如any(),anyString(),anyInt()等,用来匹配参数信息
        (7)、使用 doReturn(),doThrow(),doAnswer(),doNothing(),doCallRealMethod() 来 stub 空方法 void method

4、针对主要方法,对相关测试用例做了汇总,可以查看如下github地址,获取全部测试用例实例,供大家参考:

https://github.com/springk/mockit/tree/master/springk-mockit 

5、一些主要代码实例如下所示,实例是通过service层调用数据库层获取用户详细信息,具体代码如下:

a、UserService实例代码如下:

@Service
public class UserService {

    /**
     * DAO层
     */
    @Autowired
    private UserDao userDao;

    /**
     * 根据用户名查询数据库,获取用户信息
     * @param name
     * @return User
     */
    public User getUserInfo(String name){
        return userDao.getByName(name);
    }

     /**
     * 根据用户名删除用户信息
     * @param name
     */
    public void deletByName(String name){
        userDao.deleteByName(name);
    }
}

b、MockitTest具体实现如下:

@RunWith(MockitoJUnitRunner.class)
public class MockitTest {

    /**
     * 注入userService对象
     */
    @InjectMocks
    private UserService userService;

    /**
     * UserDao模拟数据层调用,创建UserDao实例对象
     */
    @Mock
    private UserDao userDao;


    @Before
    public void init(){
        //将UserDao实例对象注入到userService中,如果不进行此操作,userService中的userDao对象为null
        ReflectionTestUtils.setField(userService, "userDao", userDao);
    }

    @Test
    public void getUserInfoByname(){
        //模拟userDao.getByName方法的返回对象,参数为任意String类型
        Mockito.when(userDao.getByName(anyString())).thenReturn(getUserInfoInstance());

        User user= userService.getUserInfo("mockit");
        Assert.assertEquals("mockit-testname",user.getName());


    }

    private User getUserInfoInstance() {
        User user = new User();
        user.setName("mockit-testname");
        user.setSex("male");
        user.setAge(18);
        return user;
    }
}

以上方法模拟了简单封装数据层的返回实例

6、关于mock异常处理方式如下:

/**
 * mockit 抛出异常
 * 异常抛出有两种方式:
 * 1、方法有返回值的异常抛出
 * 2、void方法异常抛出 (抛出的异常要实际的异常类,不能直接抛出基类Exception())
 */
@Test
public void testMockitThrowException(){
    //1、方法有返回值的异常抛出
    Mockito.when(userDao.getByName(anyString())).thenThrow(new NullPointerException());
    User user= userService.getUserInfo("mockit");

    //2、void方法异常抛出 (抛出的异常要实际的异常类,不能直接抛出基类new Exception())
    doThrow(new RuntimeException()).when(userDao).deleteByName(anyString());
    userService.deletByName("mockit");

}

7、对静态方法mock时,使用powermock

a、引用的jar包信息

        <!-- 当方法为static时,使用powermock用来完成mock操作 -->
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito2</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-core</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- ######################################## -->

b、具体实现代码如下:

/**
 * PowermockTest
 * Mockito 不能够 mock 静态方法,可以使用 Powermock。
 * PrepareForTest 里面对应的为static方法对应的类名
 */
@RunWith(PowerMockRunner.class )
@PrepareForTest(MockitUtil.class )
public class PowermockTest {

    /**
     * mock对应静态方法
     * 另外一种方式可以自己写一个非静态的方法,对静态方法做个封装
     */
    @Test
    public void testSomething() {
        PowerMockito.mockStatic(MockitUtil.class);
        PowerMockito.when(MockitUtil.getMockitName()).thenReturn("test");
        Assert.assertEquals(MockitUtil.getMockitName(),"test");
    }
}
public class MockitUtil {

    /**
     * static 方法
     * @return Mockit
     */
    public static String getMockitName() {
        return "Mockit";
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值