背景

工作中经常用到单测,某对单测掌握的不好,所以趁此学习、总结一下。

主要参考:https://www.jianshu.com/p/0c2480b1709e、https://www.cnblogs.com/ljw-bim/p/9391770.html

一、不依赖外部方法的单测

1、待测试类

package com.shuimutong.demo.junit;

/**
 * 无依赖方法
 * @ClassName:  NotStaticMethod
 * @Description:(这里用一句话描述这个类的作用)
 * @author: 水木桶
 * @date:   2019年10月26日 上午10:37:09
 * @Copyright: 2019 [水木桶]  All rights reserved.
 */
public class NoRelayMethod {
    public static int ADD_NUM = 2;

    public static int staticAddTwo(int num) {
        return num + ADD_NUM;
    }

    /**
     * 非静态方法
     * @param num
     * @return
     */
    public int notStaticAddTwo(int num) {
        return num + ADD_NUM;
    }

    /**
     * 私有非静态方法
     * @param num
     * @return
     */
    private int privateNotStaticAddTow(int num) {
        return num + ADD_NUM;
    }
}

 2、单测类

package com.shuimutong.demo.junit;

import java.lang.reflect.Method;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

/**
 * 参照1:https://www.jianshu.com/p/0c2480b1709e
 * 参照2:https://www.cnblogs.com/ljw-bim/p/9391770.html
 * @ClassName:  NoRelayMethodTest
 * @Description:(这里用一句话描述这个类的作用)
 * @author: 水木桶
 * @date:   2019年10月26日 下午4:14:48
 * @Copyright: 2019 [水木桶]  All rights reserved.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({NoRelayMethod.class})
public class NoRelayMethodTest {
    @InjectMocks
    private NoRelayMethod noRelayMethod;

    //不需要mock,可以去除上面3个注解
    @Test
    public void staticAddTwo() {
        int num = 3;
        int result = NoRelayMethod.staticAddTwo(num);
        Assert.assertTrue(result == (num + NoRelayMethod.ADD_NUM));

    }

    //不需要mock,可以去除上面3个注解
    @Test
    public void notStaticAddTwo() {
        int num = 1;
        NoRelayMethod noRelayMethod = new NoRelayMethod();
        int result = noRelayMethod.notStaticAddTwo(num);
        Assert.assertTrue(result == (num + NoRelayMethod.ADD_NUM));
    }

    //需要mock
    //mock私有方法
    @Test
    public void privateNotStaticAddTow() throws Exception {
        Method method = PowerMockito.method(NoRelayMethod.class, "privateNotStaticAddTow", int.class);
        int num = 3;
        Object res = method.invoke(noRelayMethod, 3);
        System.out.println(res);
        Assert.assertEquals(num + NoRelayMethod.ADD_NUM, res);
    }
}

 3、备注

staticAddTwo和notStaticAddTwo方法不需要RunWith、PrepareForTest、InjectMocks这3个注解。

privateNotStaticAddTow涉及到私有方法,需要前面那3个注解。

二、有依赖外部静态方法的单测

1、待测试类

package com.shuimutong.demo.junit;

/**
 * 有依赖其他静态方法
 * @ClassName:  RelayMethod
 * @Description:(这里用一句话描述这个类的作用)
 * @author: 水木桶
 * @date:   2019年10月26日 下午3:26:01
 * @Copyright: 2019 [水木桶]  All rights reserved.
 */
public class RelayStaticMethod {
    public final static String DEFAULT_VAL = "defaultVal";
    public final static String SIGNED = "signed";

    /**
     * 依赖静态方法的
     * @param key
     * @return
     */
    public String checkAndCalc(String key) {
        String returnVal = null;
        String savedVal = RedisUtil.get(key);
        if(savedVal == null || savedVal.length() < 1) {
            returnVal = DEFAULT_VAL;
        } else {
            returnVal =  savedVal + "-" + SIGNED;
        }
        return returnVal;
    }

}

1-1、依赖外部类

package com.shuimutong.demo.junit;

import java.util.UUID;

public class RedisUtil {
    private static boolean INIT_STATE = false;

    public static String get(String key) {
        if(INIT_STATE) {
            return UUID.randomUUID().toString();
        } else {
            throw new NullPointerException("资源未初始化");
        }
    }

}

 2、单测类

package com.shuimutong.demo.junit;

import java.util.UUID;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;


@RunWith(PowerMockRunner.class)
//参考:https://www.jianshu.com/p/0c2480b1709e
//1、如果想要对某个类的静态方法进行mock,则必须在PrepareForTest后面加上相应的类名, 比如此例的RedisUtil.class。
@PrepareForTest({RedisUtil.class})
public class RelayStaticMethodTest {
    /**
     * mock依赖的静态方法
     */
    @Test
    public void checkAndCalc() {
        String key1 = "jack";
        String key2 = "john";
        String val2 = UUID.randomUUID().toString();

        //2、在对该类的某个方法进行mock之前,还必须先对整个类进行mock
        PowerMockito.mockStatic(RedisUtil.class);
        PowerMockito.when(RedisUtil.get(Mockito.eq(key1))).thenReturn(null);
        PowerMockito.when(RedisUtil.get(Mockito.eq(key2))).thenReturn(val2);

        RelayStaticMethod relayMethod = new RelayStaticMethod();
        String res = relayMethod.checkAndCalc(key1);
        System.out.println("res:" + res);
        Assert.assertEquals(RelayStaticMethod.DEFAULT_VAL, res);

        res = relayMethod.checkAndCalc(key2);
        System.out.println("res:" + res);
        Assert.assertTrue(res.contains(RelayStaticMethod.SIGNED));
    }

}

 2-1、运行结果

 三、有依赖外部非静态方法的单测

1、待测试类

package com.shuimutong.demo.junit;

/**
 * 参照1:https://www.jianshu.com/p/0c2480b1709e
 * 参照2:https://www.cnblogs.com/ljw-bim/p/9391770.html
 * @ClassName:  UserController
 * @Description:(这里用一句话描述这个类的作用)
 * @author: 水木桶
 * @date:   2019年10月26日 下午4:14:30
 * @Copyright: 2019 [水木桶]  All rights reserved.
 */
public class UserController {
    private UserService userService = new UserService();

    public User saveUser(String name) {
        return userService.save(name);
    }
}

1-1、依赖非静态类

package com.shuimutong.demo.junit;

public class UserService {
    public User save(String name) {
        System.out.println("UserService--save--name:" + name);
        User u = new User(name);
        u.setId((long)(Math.random() * 1000) + 2);
        return u;
    }
}

 1-2、相关类User

package com.shuimutong.demo.junit;

public class User {
    private long id;
    private String name;

    public User(String name) {
        this.name = name;
    }
    public User() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + "]";
    }
}

 2、单测类

package com.shuimutong.demo.junit;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

/**
 * 参照1:https://www.jianshu.com/p/0c2480b1709e
 * 参照2:https://www.cnblogs.com/ljw-bim/p/9391770.html
 * @ClassName:  UserControllerTest
 * @Description:(这里用一句话描述这个类的作用)
 * @author: 水木桶
 * @date:   2019年10月26日 下午4:13:51
 * @Copyright: 2019 [水木桶]  All rights reserved.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({UserController.class})
public class UserControllerTest {
    @Mock
    private UserService userService;
    @InjectMocks
    private UserController userController;

    @Test
    public void saveUser() {
        String name = "jack";
        //执行userService的实际方法
        PowerMockito.when(userService.save(Mockito.anyString())).thenCallRealMethod();
        User returnUser = userController.saveUser(name);
        System.out.println("returnUser:" + returnUser);
        Assert.assertTrue(returnUser.getId() > 1);

        long id = 1L;
        User u1 = new User(name);
        u1.setId(id);
        System.out.println("u1:" + u1);
        //mock userService的方法
        Mockito.when(userService.save(name)).thenReturn(u1);
        returnUser = userController.saveUser(name);
        //verify验证mock次数
        Mockito.verify(userService, Mockito.times(2)).save(name);
        Assert.assertEquals(id, returnUser.getId());
        Assert.assertEquals(u1, returnUser);
        System.out.println("returnUser:" + returnUser);
    }
}

2-1、执行结果

四、相关环境

1、依赖jar

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.10.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>

2、源码地址

https://gitee.com/simpleha/useDemo/tree/master/junit

12-29 23:49