Java单元测试实践-06.Mock后Stub静态方法

news/2024/11/9 12:44:04

Java单元测试实践-00.目录(9万多字文档+700多测试示例)
https://blog.csdn.net/a82514921/article/details/107969340

1. Mock后Stub静态方法

以下使用PowerMockito对包含静态方法的类进行Mock,再使用Mockito/PowerMockito对静态方法进行Stub,可以改变被Mock/Stub方法的行为。

1.1. Mock包含静态方法的类

参考“Mocking static methods”( https://github.com/powermock/powermock/wiki/MockStatic#mocking-static-methods )。

使用PowerMockito对静态方法对应的类进行Mock,除了需要在测试用例的类级别使用@RunWith(PowerMockRunner.class)注解外,还需要以下操作:

  • 在测试用例的类级别使用@PrepareForTest(包含静态方法的类.class)注解,@PrepareForTest注解支持通过数组指定多个类的Class对象;

  • 使用PowerMockito.mockStatic(包含静态方法的类.class)对类(的所有方法)进行Mock。

1.1.1. 使用@PrepareForTest注解

对包含静态方法的类进行Mock时,需要使用@PrepareForTest注解指定需要Mock的类。若不指定,在执行PowerMockito.mockStatic()方法时会出现异常,异常类型为“org.powermock.api.mockito.ClassNotPreparedException”,异常信息为“The class … not prepared for test”。可参考示例TestStPuNVNoPrepare类。

1.1.2. PowerMockito.mockStatic()方法

对包含静态方法的类进行Mock时,需要执行PowerMockito.mockStatic()方法对需要Mock的类进行Mock。若不执行上述方法,执行Mockito.when()方法会出现异常,异常类型为“org.mockito.exceptions.misusing.InvalidUseOfMatchersException”,异常信息为“Misplaced or misused argument matcher detected here:”。可参考示例TestStPuNVNoMock类。

1.2. Stub静态公有非void方法

Mockito.when()方法返回类型为OngoingStubbing,OngoingStubbing接口在org.mockito.stubbing包中,提供thenReturn()、thenThrow()、thenAnswer()、thenCallRealMethod()等方法。

1.2.1. 修改返回值

使用Mockito.when(包含静态方法的类.静态方法(Stub参数条件)).thenReturn(),支持对静态公有非void方法进行Stub,返回指定的值,thenReturn()方法的参数指定返回值。当调用被Stub的方法时,真实方法不会被调用。

示例如下,可参考示例TestStPuNVThenReturnPrepareClass类test1方法。

Mockito.when(TestStaticPublicNonVoid1.test1(TestConstants.FLAG1, testTableEntity)).thenReturn(TestConstants.MOCKED);

使用PowerMockito.when方法也支持修改返回值。 可参考示例TestStPuNVThenReturnPrepareClass类test2方法。

支持对无参数的静态公有非void方法修改返回值。 可参考示例TestStPuNVThenReturnPrepareMethod类。

@PrepareForTest注解除支持在类级别使用外,也支持在方法级别使用。 可参考示例TestStPuNVThenReturnPrepareMethod类。

Mock、Stub等操作可以在不包含@Before、@Test、@PrepareForTest注解的类中执行。 可参考示例TestStPuNVThenReturnRun1、TestStPuNVThenReturnMock1类。

在执行Mockito/PowerMockito.when()方法时,参数可使用指定的固定值,或Mockito.any()等方法。在调用被Stub的方法时,若参数满足Mock条件,会执行指定的Stub操作。Mockito.any()等条件处理在后续说明。

1.2.1.1. 使用@PrepareForTest注解fullyQualifiedNames参数

在使用@PrepareForTest注解时,除了可以通过value参数指定需要@PrepareForTest注解处理的类,还可以通过fullyQualifiedNames参数指定。

在通过fullyQualifiedNames参数指定时,需要指定需要@PrepareForTest注解处理的类的完整名称,支持使用通配符指定类名或包名,示例如下,可参考示例TestStPuNVThenReturnPrepareName类。

@PrepareForTest(fullyQualifiedNames = "com.adrninistrator.static1.TestStaticPublicNonVoid1")

@PrepareForTest(fullyQualifiedNames = "com.adrninistrator.static1.TestStaticPublicNonVoid1*")

@PrepareForTest(fullyQualifiedNames = "com.adrninistrator.static1.*")

1.2.2. 抛出异常

使用Mockito.when(包含静态方法的类.静态方法(Stub参数条件)).thenThrow(),支持对静态公有非void方法进行Stub,抛出指定的异常,thenThrow()方法的参数指定了需要抛出的异常对象。示例如下。

Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class)))
        .thenThrow(new RuntimeException(TestConstants.MOCKED));

若被Stub的方法未声明抛出异常,thenThrow可以指定RuntimeException或其子类。可参考示例TestStPuNVThenThrow类test1、test2方法。

若被Stub的方法有声明抛出异常,thenThrow指定的异常类型需要与方法声明的异常类型相符。可参考示例TestStPuNVThenThrow类test3方法。

1.2.3. 使用Answer实现回调

使用Mockito.when(包含静态方法的类.静态方法(Stub参数条件)).thenAnswer(),支持对静态公有非void方法进行Stub,实现回调,执行自定义操作。

thenAnswer()方法的参数需要为Answer接口实现类,Answer接口在定义时使用了范型“public interface Answer<T>”,实现Answer接口时,需要指定范型对应的返回类型,并实现“T answer(InvocationOnMock invocation) throws Throwable;”方法,且answer()方法的返回类型应与Answer接口范型类型相同。Answer实现类如下所示:

public class Answer1 implements Answer<String> {

    @Override
    public String answer(InvocationOnMock invocation) throws Throwable {

        return (String) invocation.callRealMethod();
    }
}

1.2.3.1. 在Answer中执行真实方法

在Answer接口的实现类中,answer()方法的返回值将作为函数被Stub生效后的返回值;在answer()方法中调用invocation.callRealMethod()方法,可以执行真实方法,返回值可强制类型转换为所需的类型。可参考示例AnswerStaticPublicNonVoid1类。

@Override
public String answer(InvocationOnMock invocation) throws Throwable {
	return (String) invocation.callRealMethod();
}

在thenAnswer()方法中指定上述Answer接口的实现类的实例,可以使被Stub的方法执行真实方法。示例如下,可参考示例TestStPuNVThenAnswerCallRealMethod1类test1方法。

Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class))).thenAnswer
        (new AnswerStaticPublicNonVoid1());

1.2.3.2. 在Answer中修改方法返回值

在Answer接口的实现类中,指定answer()方法的返回值,即可修改被Stub方法的返回值。如以下示例中,被Stub的方法返回值被修改为"…":

public String answer(InvocationOnMock invocation) throws Throwable {
	return "...";
}

1.2.3.3. 在Answer中抛出异常

在Answer接口的实现类的answer()方法中抛出异常,可使被Stub方法抛出指定异常。如以下示例中,被Stub的方法会抛出异常:

public String answer(InvocationOnMock invocation) throws Throwable {
	throw new RuntimeException("...");
}

1.2.3.4. 使用匿名类实现Answer

使用匿名类也可以作为Answer接口的实现类,如下所示。可参考示例TestStPuNVThenAnswerCallRealMethod1类test2方法。

Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class))).thenAnswer
        (new Answer<String>() {
            @Override
            public String answer(InvocationOnMock invocation) throws Throwable {
                return (String) invocation.callRealMethod();
            }
        });

1.2.3.5. 使用lambda表达式实现Answer接口

参考“37. Java 8 Custom Answer Support ”( https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#Java_8_Custom_Answers )。

由于Answer接口只有一个方法,可在Java 8中使用lambda表达式实现它。

当使用lambda表达式时,可以使用“invocation -> {}”的形式,在“{}”中可以进行比较复杂的操作,如下所示。可参考示例TestStPuNVThenAnswerCallRealMethod1类test3方法。

Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class)))
        .thenAnswer(invocation -> {
                    return invocation.callRealMethod();
                }
        );

也可以使用“invocation -> …”的形式,直接指定函数的返回值或执行真实方法,如下所示。可参考示例TestStPuNVThenAnswerCallRealMethod1类test4、test5方法。

Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class)))
        .thenAnswer(invocation -> "...");
		
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class)))
        .thenAnswer(invocation -> invocation.callRealMethod());		

1.2.3.6. 获取请求参数

在Answer接口实现类( 以下简称Answer )的answer()方法中,调用InvocationOnMock invocation参数的getArguments方法可以获取调用该方法时的全部参数。

调用getArgument方法可以获取指定序号的参数。( Mockito 1.*与Mockito 2.*版本的getArgument方法名不同,后续内容会说明 )

调用getArgument方法时,参数的序号从0开始。

当使用getArgument(int index, Class<T> clazz)方法时,若需要获取的参数为基本类型,传入的clazz应使用对应的包装类;当使用getArgument(int index)方法时则不需要指定类型。

可参考示例TestCommonUtil类getMockArg方法,当为Mockito 2.*以上版本时,使用InvocationOnMock.getArgument(int index, Class<T> clazz)方法获取指定序号的参数。也可以使用InvocationOnMock.getArgument(int index)方法,不需要指定参数类型,更便捷。示例如下:

int arg1 = TestCommonUtil.getMockArg(invocation, 0, Integer.class);
String arg2 = invocation.getArgument(1, String.class);
TestTableEntity arg3 = invocation.getArgument(2);

在获取请求参数后,可以检查参数是否符合预期,或对参数进行记录等。可参考示例TestStPuNVThenAnswerGetReqArgs1类。

还可以根据请求参数决定修改返回值、抛出异常或执行真实方法。可参考示例TestStPuNVThenAnswerModifyRsp1类。

1.2.3.7. 修改调用参数并执行真实方法

在Answer中,可以修改调用参数并执行真实方法,但意义不大,因为请求参数修改后,在被测试代码中使用的参数值也被修改,后续若继续使用了参数,可能会产生难以预计的影响。

以下为在Answer中,对于不同类型的参数支持修改的情况。

  • 基本类型

在Answer中,无法对基本类型的参数进行修改。

  • 包装类

在Answer中,可以对包装类参数进行修改,例如Integer类中使用int value变量保存实际的值,可以通过反射修改value变量值,从而修改Integer类的值。可参考示例TestStPuNVThenAnswerModifyArg1类test1方法。

  • 没有set方法的类

对于没有set方法的类,可以在Answer中通过反射修改其值,例如String类中使用char value[]保存实际的值,可以通过反射修改value变量值,从而修改String类的值。可参考示例TestStPuNVThenAnswerModifyArg1类test2方法。

  • 有set方法的类

对于有set方法的类,可以在Answer中通过set方法修改其值。可参考示例TestStPuNVThenAnswerModifyArg1类test3方法。

1.2.3.8. 获取调用方法信息

Answer的answer()方法的InvocationOnMock invocation参数,对应的类为org.mockito.internal.invocation.InterceptedInvocation( Mockito 1.*与Mockito 2.*版本的InvocationOnMock接口对应的实现类不同,后续内容会说明 ),在InterceptedInvocation类中包含变量Location location。

Location location对应的类为org.mockito.internal.debugging.LocationImpl,LocationImpl类实现了org.mockito.invocation.Location接口,实现了toString()、getSourceFile()方法。

Location.toString()方法可获取可读性好的源代码位置,返回结果包含了调用方法的完整类名与包名,如“at adrninistrator.test.testmock.static1.mock.public1.non_void.answer.TestStPuNVThenAnswerGetLocation1.test(TestStPuNVThenAnswerGetLocation1.java:41)”。

Location.getSourceFile()方法可获取源文件位置,返回结果如“TestStPuNVThenAnswerGetLocation1.java”。可参考示例TestStPuNVThenAnswerGetLocation1类。

可以根据调用方法信息决定修改返回值、抛出异常或执行真实方法。可参考示例TestStPuNVThenAnswerGetLctMdfRsp1类。

1.2.3.9. 判断指定方法是否执行

在Answer的answer()方法中,可以记录方法的执行次数或是否执行的标志,在测试代码中可以判断被测试代码指定方法在特定条件下的执行次数,或是否有执行过,适用于检查特定交易完成后,是否有执行后续的处理( 如发送短信/邮件/微信通知等 )。示例如下:

TestAnswer testAnswer = new TestAnswer(TestConstants.FLAG1);

Mockito.when(TestStaticPublicNonVoid1.test4(Mockito.anyString())).thenAnswer(testAnswer);

TestStaticPublicNonVoid1.test4(TestConstants.FLAG1);
assertTrue(testAnswer.isCalled());

static class TestAnswer implements Answer<String> {

	private boolean called;
	private String flag;

	public TestAnswer(String flag) {
		this.flag = flag;
	}

	public boolean isCalled() {
		return called;
	}

	@Override
	public String answer(InvocationOnMock invocation) throws Throwable {

		String arg1 = invocation.getArgument(0);

		if (flag.equals(arg1)) {
			called = true;
		}

		return TestConstants.MOCKED;
	}
}

可参考示例TestStPuNVThenAnswerCheckCalled1类。

1.2.3.10. 延长方法执行耗时

在Answer的answer()方法中,可以通过sleep延长方法执行耗时,再执行真实方法,可以模拟交易超时的情况。可参考示例TestStPuNVThenAnswerSpendTime类。

1.2.4. 使用verify判断方法的执行次数

使用Mockito类的verify方法可以判断被Mock类的静态公有非void方法的执行次数,需要分两步执行:

  • 首先执行“Mockito.verify(包含静态方法的类.class, VerificationMode对象);”
  • 再执行“包含静态方法的类.静态方法(Verify参数条件)”

在每个Mockito.verify()方法后都需要执行“包含静态方法的类.静态方法()”,否则会出现“org.mockito.exceptions.misusing.UnfinishedVerificationException: Missing method call for verify(mock) here:”异常。在Mockito.verify()方法后执行“包含静态方法的类.静态方法()”时,不会执行真实方法。

对于VerificationMode对象,可以使用Mockito.times()等返回类型为VerificationMode的方法的返回对象,设置预期的执行次数,如下所示:

方法说明
Mockito.times(int wantedNumberOfInvocations)方法应执行指定次数
Mockito.never()方法应未执行过
Mockito.atLeastOnce()方法应执行至少一次
Mockito.atLeast(int minNumberOfInvocations)方法应执行至少指定次数
Mockito.atMostOnce()方法应执行至多一次
Mockito.atMost(int maxNumberOfInvocations)方法应执行至多指定次数

在执行“包含静态方法的类.静态方法()”时,Verify参数条件可以指定具体值,也可以使用Mockito.any()等ArgumentMatchers类的方法,支持使用Mockito.argThat()( 在后续内容说明 )。

当Verify参数条件指定具体值时,会检查方法的执行次数,以及参数是否等于对应的具体值;当参数使用Mockito.any()等方法时,会检查方法的执行次数,以及参数是否满足Mockito.any()等方法指定的条件。

当被检查的方法已执行过,但执行的参数不满足指定的参数条件时,不统计执行次数。

使用Mockito.verify()方法判断静态公有非void方法执行次数的示例如下,可参考示例TestStPuNVVerify类test1方法。

Mockito.verify(TestStaticPublicNonVoid1.class, Mockito.times(0));
TestStaticPublicNonVoid1.test1(TestConstants.FLAG1, testTableEntity1);

Mockito.verify(TestStaticPublicNonVoid1.class, Mockito.times(0));
TestStaticPublicNonVoid1.test1(Mockito.argThat(argument -> TestConstants.FLAG1.equals(argument)), Mockito
        .argThat(argument -> testTableEntity1.equals(argument)));

Mockito.verify(TestStaticPublicNonVoid1.class, Mockito.times(3));
TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class));

Mockito.verify方法也可以使用PowerMockito.verifyStatic方法,示例如下,可参考示例TestStPuNVVerify类test2方法。

PowerMockito.verifyStatic(TestStaticPublicNonVoid1.class, Mockito.times(1));
TestStaticPublicNonVoid1.test1(TestConstants.FLAG1, testTableEntity1);

Mockito类的只包含一个参数的verify方法“verify(T mock)”中,调用了verify(mock, times(1))方法,即验证对应的方法应执行了一次。

1.2.4.1. 使用Captor获取调用参数

在使用verify判断被Mock类的方法执行次数时,还可以使用Captor获取调用参数,需要分两步进行:

  • 创建ArgumentCaptor<T>对象,在创建时需要指定范型对应的参数类型
  • 在执行verify操作的“包含静态方法的类.静态方法()”操作时,指定的参数使用ArgumentCaptor对象的capture()方法返回对象,每个需要获取的参数都需要指定一个单独的ArgumentCaptor对象

以上操作执行完毕后,ArgumentCaptor对象中包含了调用方法时使用的参数信息。

调用ArgumentCaptor对象的getValue()方法,可以获取到最后一次调用时的参数值。

调用ArgumentCaptor对象的getAllValues()方法,可以获取到每次调用时的全部参数值列表。返回的列表元素数量与方法调用的次数相同,每次调用方法的参数在列表中对应的序号递增。

使用Mockito.verify()判断静态公有非void方法执行次数,并使用Captor获取调用参数的示例如下,可参考示例TestStPuNVVerifyCaptor类。

ArgumentCaptor<String> argCaptor1 = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<TestTableEntity> argCaptor2 = ArgumentCaptor.forClass(TestTableEntity.class);

Mockito.verify(TestStaticPublicNonVoid1.class, Mockito.times(1));
TestStaticPublicNonVoid1.test1(argCaptor1.capture(), argCaptor2.capture());

String arg1 = argCaptor1.getValue();
TestTableEntity arg2 = argCaptor2.getValue();

List<String> arg1List = argCaptor1.getAllValues();
List<TestTableEntity> arg2List = argCaptor2.getAllValues();

1.2.5. 执行真实方法

使用Mockito.when(包含静态方法的类.静态方法(Stub参数条件)).thenCallRealMethod(),支持对静态公有非void方法进行Stub,执行真实方法。示例如下,可参考示例TestStPuNVThenCallRealMethod类。

Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class)))
        .thenCallRealMethod();

1.3. Stub静态公有void方法

Mockito.when()不支持对void方法进行Stub,需要使用PowerMockito类的when()方法,对静态公有void方法进行Stub。

1.3.1. 抛出异常

对静态公有void方法进行Stub,抛出指定的异常,可使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenThrow()。示例如下,可参考示例TestStPuVThenThrow类。

PowerMockito.when(TestStaticPublicVoid1.class, TestStaticPublicVoid1.NAME_TEST1, Mockito.any(StringBuilder
        .class)).thenThrow(new RuntimeException(TestConstants.MOCKED));

1.3.2. 使用Answer实现回调

对静态公有void方法进行Stub,使用Answer实现回调,可使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenAnswer()。示例如下,可参考示例TestStPuVThenAnswer类。

AnswerStaticPublicVoid1 answerStaticPublicVoid1 = new AnswerStaticPublicVoid1();

PowerMockito.when(TestStaticPublicVoid1.class, TestStaticPublicVoid1.NAME_TEST1, Mockito.any(StringBuilder
        .class)).thenAnswer(answerStaticPublicVoid1);

对于Answer的使用,可参考前文。

1.3.3. 使用verify判断方法的执行次数

判断被Mock类的静态公有void方法执行次数,可使用Mockito.verify()方法,与判断静态公有非void方法执行次数时的步骤相同。示例如下,可参考示例TestStPuVVerify类。

Mockito.verify(TestStaticPublicVoid1.class, Mockito.times(1));
TestStaticPublicVoid1.test1(stringBuilder);

1.3.3.1. 使用Captor获取调用参数

判断被Mock类的静态公有void方法执行次数,并使用Captor获取调用参数,可使用Mockito.verify()方法及ArgumentCaptor类,与处理非void方法时的步骤相同。示例如下,可参考示例TestStPuVVerifyCaptor类。

ArgumentCaptor<StringBuilder> argCaptor1 = ArgumentCaptor.forClass(StringBuilder.class);

Mockito.verify(TestStaticPublicVoid1.class, Mockito.times(1));
TestStaticPublicVoid1.test1(argCaptor1.capture());

1.3.4. 执行真实方法

对静态公有void方法进行Stub,执行真实方法,可使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenCallRealMethod()。示例如下,可参考示例TestStPuVThenCallRealMethod类。

PowerMockito.when(TestStaticPublicVoid1.class, TestStaticPublicVoid1.NAME_TEST1, Mockito.any(StringBuilder
        .class)).thenCallRealMethod();

1.3.5. doNothing

使用PowerMockito.doNothing().when(包含静态方法的类.class, 静态方法名, Stub参数条件),支持对静态公有void方法进行Stub,使其什么也不做。示例如下,可参考示例TestStPuVDoNothing类。

PowerMockito.doNothing().when(TestStaticPublicVoid1.class, TestStaticPublicVoid1.NAME_TEST1, Mockito.any
        (StringBuilder.class));

1.4. Stub静态私有非void方法

Mockito不支持对私有方法进行Stub,需要使用PowerMockito类的when()方法,对静态私有方法进行Stub。

通过反射调用静态私有方法,或通过对应的公有方法间接调用静态私有方法时,Stub均能生效。

  • 修改返回值

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenReturn(),支持对静态私有非void方法进行Stub,修改返回值。

通过静态方法对应的类的公有方法间接调用私有方法时,由于该类被执行了PowerMockito.mockStatic(),导致默认情况下全部方法均不会执行真实方法,因此需要将对应的公有方法Stub为执行真实方法,如下所示:

Mockito.when(TestStaticPrivateNonVoid1.testPublic1(Mockito.anyString(), Mockito.any(TestTableEntity.class)))
        .thenCallRealMethod();
PowerMockito.when(TestStaticPrivateNonVoid1.class, TestStaticPrivateNonVoid1.NAME_TEST1, TestConstants.FLAG1,
        testTableEntity).thenReturn(TestConstants.MOCKED);

可使用Whitebox.invokeMethod方法通过反射执行私有方法,使用方式为“Whitebox.invokeMethod(包含静态私有方法的类.class, 静态私有方法名, 参数)”,返回类型为范型,不需要强制类型转换,示例如下:

String str = Whitebox.invokeMethod(TestStaticPrivateNonVoid1.class, TestStaticPrivateNonVoid1.NAME_TEST1,
        TestConstants.FLAG1, testTableEntity);

对于有参数的方法,及没有参数的方法进行Stub,Stub均能生效,可参考示例TestStPrNVThenReturn1、TestStPrNVThenReturn2类。

  • 抛出异常

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenThrow(),支持对静态私有非void方法进行Stub,抛出异常。可参考示例TestStPrNVThenThrow1、TestStPrNVThenThrow2类。

  • 使用Answer实现回调

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenAnswer(),支持对静态私有非void方法进行Stub,使用Answer实现回调。可参考示例TestStPrNVThenAnswer1类。

  • 使用verify判断方法的执行次数

使用Mockito类的verify方法可以判断被Mock类的静态私有非void方法执行次数,需要分两步执行:

  1. 首先执行“Mockito.verify(包含静态方法的类.class, VerificationMode对象);”
  2. 再通过反射执行包含静态方法的类的静态方法,参数使用Verify参数条件

在每个Mockito.verify()方法后需要通过反射执行包含静态方法的类的静态方法。示例如下,可参考示例TestStPrNVVerify类。

Mockito.verify(TestStaticPrivateNonVoid1.class, Mockito.times(1));
Whitebox.invokeMethod(TestStaticPrivateNonVoid1.class, TestStaticPrivateNonVoid1.NAME_TEST1, TestConstants
        .FLAG1, testTableEntity1);
  • 使用Captor获取调用参数

判断静态私有非void方法执行次数,并使用Captor获取调用参数,与处理静态公有方法时的步骤类似,将“执行“包含静态方法的类.静态方法()””步骤替换为“通过反射执行包含静态方法的类的静态方法”即可。可参考示例TestStPrNVVerifyCaptor类。

  • 执行真实方法

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenCallRealMethod(),支持对静态私有非void方法进行Stub,执行真实方法。可参考示例TestStPrNVThenCallRealMethod类。

1.5. Stub静态私有void方法

Stub静态私有void方法的处理,与Stub静态私有非void方法的处理类似。

  • 抛出异常

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenThrow(),支持对静态私有void方法进行Stub,抛出异常。可参考示例TestStPrVThenThrow类。

  • 使用Answer实现回调

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenAnswer(),支持对静态私有void方法进行Stub,使用Answer实现回调。可参考示例TestStPrVThenAnswer类。

  • 使用verify判断方法的执行次数

判断被Mock类的静态私有void方法执行次数,可使用Mockito.verify()方法,与判断静态私有非void方法执行次数时的步骤相同。可参考示例TestStPrVVerify类。

  • 使用Captor获取调用参数

判断被Mock类的静态私有void方法执行次数,并使用Captor获取调用参数,可使用Mockito.verify()方法及ArgumentCaptor类,与处理静态私有非void方法的步骤相同。可参考示例TestStPrVVerifyCaptor类。

  • 执行真实方法

使用PowerMockito.when(包含静态方法的类.class, 静态方法名, Stub参数条件).thenCallRealMethod(),支持对静态私有void方法进行Stub,执行真实方法。可参考示例TestStPrVThenCallRealMethod类。

  • doNothing

使用PowerMockito.doNothing().when(包含静态方法的类.class, 静态方法名, Stub参数条件),支持对静态私有void方法进行Stub,使其什么也不做。可参考示例TestStPrVDoNothing类。

1.6. 其他内容

1.6.1. PowerMockito.mockStatic()执行多次

当PowerMockito.mockStatic()方法执行多次时,会对静态方法所在的类重新进行Mock,未被Stub的方法行为受到指定的默认Answer控制,之前对静态方法设置的Stub均会失效。

例如对类A执行了PowerMockito.mockStatic()方法后,执行Mock.when().then…()对类A的静态方法f1()进行Stub,再次对类A执行PowerMockito.mockStatic()方法,会使类A的所有静态方法行为受到指定的默认Answer(不指定时默认返回空值)控制,对类A的静态方法f1()进行的Stub会失效。示例如下:

PowerMockito.mockStatic(C1.class);

Mockito.when(C1.f1(TestConstants.FLAG1)).thenReturn(TestConstants.FLAG1);

String str = C1.f1(TestConstants.FLAG1);
assertEquals(TestConstants.FLAG1, str);

PowerMockito.mockStatic(C1.class);

str = C1.f1(TestConstants.FLAG1);
assertNull(str);

可参考示例TestStMockReset类。

1.6.2. 多次执行Stub

参考“2. How about some stubbing?”( https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#stubbing )。当多次对同一个方法使用相同的参数条件进行Stub时,最后一次Stub更为重要。

当多次对同一个方法使用相同的参数条件进行Stub时,最后一次执行的Stub会生效。

例如先对C1.f1()方法进行Stub,使其返回"1",再对其使用相同的参数条件进行Stub,使其返回"2",在则执行C1.f1()方法时,若满足Stub条件,则会返回"2"。

可参考示例TestStMockStubMulti类。

1.6.3. 对相同方法的不同条件的Stub

对同一个方法使用不同的参数条件设置Stub时,不会产生相互影响,均能够生效。

例如对C1.f1(String str)方法进行Stub,当调用参数等于"1"时返回"1",当调用参数等于"2"时返回"2",以上Stub能够共存,不会相互覆盖。

可参考示例TestStMockStubDiff类。


http://www.niftyadmin.cn/n/4057571.html

相关文章

Java单元测试实践-07.Answer与未Stub的静态方法

Java单元测试实践-00.目录&#xff08;9万多字文档700多测试示例&#xff09; https://blog.csdn.net/a82514921/article/details/107969340 1. Answer与未Stub的静态方法 以下主要说明&#xff0c;在对静态方法所在的类执行PowerMockito.mockStatic()方法时&#xff0c;指定…

歌词

我爸叫李刚 网络神曲的歌词&#xff1a;横行路中央&#xff0c;轿车轻飞扬。黄土地里养育着咱那霸道的爹娘。平凡的摸样&#xff0c;可咱爸是局长&#xff0c;只手遮天的大树&#xff0c;还有神秘的力量。我爸叫李刚&#xff0c;大名鼎鼎的李刚&#xff0c;李是李世民的李啊&am…

Java单元测试实践-09.Mockito的Stub参数条件

Java单元测试实践-00.目录&#xff08;9万多字文档700多测试示例&#xff09; https://blog.csdn.net/a82514921/article/details/107969340 1. Mockito的Stub参数条件 使用Mockito.when().then…()/Mockito.do…().when()等对方法进行Stub时&#xff0c;需要为每个参数指定S…

Java单元测试实践-10.Mock非静态方法

Java单元测试实践-00.目录&#xff08;9万多字文档700多测试示例&#xff09; https://blog.csdn.net/a82514921/article/details/107969340 1. Mock非静态方法 对非静态方法的进行Mock等处理时&#xff0c;部分情况与对Spring的Component组件的处理类似&#xff0c;主要在后…

Java单元测试实践-11.Mock后Stub Spring的@Component组件

Java单元测试实践-00.目录&#xff08;9万多字文档700多测试示例&#xff09; https://blog.csdn.net/a82514921/article/details/107969340 1. Spring Context加载次数 在使用PowerMock时&#xff0c;每执行一个测试类&#xff0c;Spring Context都会重新加载一次&#xff0…

Java单元测试实践-12.Answer与未Stub的Spring组件方法

Java单元测试实践-00.目录&#xff08;9万多字文档700多测试示例&#xff09; https://blog.csdn.net/a82514921/article/details/107969340 1. Answer与未Stub的Spring组件方法 1.1. 未Stub的方法的返回值 对于Spring的Component组件的Mock对象未Stub的方法&#xff0c;返回…