当前位置:   article > 正文

java:单元测试(UT)_java ut

java ut

原则
1、分析需求场景
2、依据场景列出判断分支
3、依据分支编写测试用例,若方法具有多层调用,则依据逻辑,判断入参变化点,针对具有入参变化点的方法编写UT
4、编写实现逻辑

框架
本次使用Junit进行测试,基于Junit的模拟框架使用mockito配合powermock
Junit:每个测试都是一个方法,比较输入输出以实现代码验证
TestNG:测试被组织的类,与Junit相同,但是要运行TestNG,必须添加配置
基于Junit模拟框架:mockito、easymock、powermock

基础知识:(待补充。。。)
Mockito
Powermock

mock与spy的区别:
mock:类中所有的方法均被置空,均返回null,不真实执行方法内部逻辑
spy:类中所有方法均真实执行

下面将针对写单测时遇到的问题有针对性列举
1、针对类A方法doIt进行单测时,调用了其中的public static void getResult(String s),而且getResult中调用了工具类的private static int empty(String s)方法
目标是执行getResult进入方法内执行,而empty不真实执行
解决方法:
1.1首先分析
工具类需要@PrepareForTest进行声明;
static方法需要使用PowerMock进行mock;
进入类A的方法中真正执行,需要间谍spy
某些方法不真正执行,使用doReturn方式
1.2实战
被测类:

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class A{
    private static int empty() {
        System.out.println("enter empty");
        return 1;
    }

    public static int getResult() {
        System.out.println("realprint");
        int a = empty();
        System.out.println(a);
        return 1;
    }

    public static int doIt() {
        return SumTwo.getResult();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

测试类:

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

import program.SumTwo;

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class PowermockTest {
    @Test
    public void sumtwoTest() throws Exception {
        PowerMockito.mockStatic(A.class);
        PowerMockito.spy(A.class);

        PowerMockito.doReturn(2).when(A.class, "empty");

        int result = A.doIt();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

该测试用例的运行结果符合预期,empty方法不执行,因此不会打印“123”
打印结果如下:

realprint
2
  • 1
  • 2

2、when中调用了类的方法,方法所在类必须先在prepare中声明出处,并且需要提前mock,若类中该方法为static则需要对该类用mockstatic,以便执行该方法
eg:

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

import program.SumTwo;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SumTwo.class)
public class PowermockTest {
    @Test
    public void sumtwoTest() throws Exception {
        PowerMockito.mockStatic(SumTwo.class);

        PowerMockito.doReturn(2).when(SumTwo.class, "empty");

        int result = SumTwo.doIt();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

如上测试代码可以正常运行
当我们将mockstatic修改为mock,会出现如下报错:

java.lang.NullPointerException
	at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing(PowerMockitoStubberImpl.java:68)
	at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:43)
	at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:111)
	at PowermockTest.sumtwoTest(PowermockTest.java:17)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3、对例1的扩展,模拟执行的private方法带入参
注意,若不想真正执行该private方法,除了使用doReturn外,需要模拟传入的入参与代码真正执行时的入参一致,否则仍然会执行该private方法。

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

import program.SumTwo;

import static org.mockito.Matchers.any;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SumTwo.class)
public class PowermockTest {
    @Test
    public void sumtwoTest() throws Exception {
        PowerMockito.spy(SumTwo.class);
        PowerMockito.doReturn(2).when(SumTwo.class, "empty", 3);
		int result = SumTwo.doIt();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

运行上述调用代码,执行后,打印结果如下

realprint
enter empty
1
  • 1
  • 2
  • 3

若我们修改empty的入参,为真实入参1则会出现如下打印结果

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

import program.SumTwo;

import static org.mockito.Matchers.any;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SumTwo.class)
public class PowermockTest {
    @Test
    public void sumtwoTest() throws Exception {
        PowerMockito.spy(SumTwo.class);
        PowerMockito.doReturn(2).when(SumTwo.class, "empty", 1);
		int result = SumTwo.doIt();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
realprint
2
  • 1
  • 2

4、当对象创建在方法中进行,对该方法进行UT时,需要通过PowerMock的whenNew方法创建该对象,针对该对象进行打桩。
PowerMockito.whenNew(A.class).withArguments(arg1, arg2,… argn).thenReturn(result);

5、针对ENUM类型的单例,做UT时,使用白盒

public enum SingletonObject {
    INSTANCE;
    private int num;

    protected void setNum(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

单例调用:

public class SingletonConsumer {
    public String consumeSingletonObject() {
        return String.valueOf(SingletonObject.INSTANCE.getNum());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5

UT:

import static org.junit.Assert.*;
import static org.powermock.api.mockito.PowerMockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

@RunWith(PowerMockRunner.class)
@PrepareForTest({SingletonObject.class})
public class SingletonConsumerTest {
    @Test
    public void testConsumeSingletonObject() throws Exception {
    	**// 真实执行单例类的某个方法使用spy,若不执行,使用mock(SingletonObject.class)**
        SingletonObject mockInstance = spy(SingletonObject.INSTANCE);
        Whitebox.setInternalState(SingletonObject.class, "INSTANCE", mockInstance);

        when(mockInstance.getNum()).thenReturn(42);

        assertEquals("42", new SingletonConsumer().consumeSingletonObject());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/274400
推荐阅读
相关标签
  

闽ICP备14008679号