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

Java单元测试中Mock技术的核心原理与Mockito实战指南 在软件工程实践中,单元测试是确保代码质量的关键环节,其核心原则在于隔离性——即测试应聚焦于单一单元的逻辑,排除外部依赖的干扰。为实现这一目标,Mock(模拟)技术应运而生,它通过创建依赖对象的替身,预设其行为与返回值,从而将测试与数据库、网络服务等不稳定因素解耦。这一机制不仅大幅提升了测试执行速度与结果稳定性,更推动了测试驱动开发(TDD)的落地。作为Java生态中最主流的Mock框架,Mockito提供了强大的打桩(Stubbing)与行为验证(Verification)能力,遵循Given-When-T 阅读详情

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

1. Answer与未Stub的静态方法

以下主要说明,在对静态方法所在的类执行PowerMockito.mockStatic()方法时,指定的Answer对未被Stub的静态方法的影响。

Answer可以看作执行被Mock/Stub的方法时的回调处理。

2. 未Stub的方法的返回值

当静态方法所在的类通过PowerMockito.mockStatic()进行Mock,对于未被Stub的静态方法,默认情况下,返回值为返回类型对应的默认值。

参考“2. How about some stubbing?”( https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#stubbing )。默认情况下,对于所有有返回值的方法,Mock将根据情况返回null,原始/原始包装器值或空集合。例如,对于int/Integer返回0,对于boolean/Boolean返回false,对于String返回null等。

关于Java基本类型的默认值,可参考“Default Values”( https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html )。

未Stub的方法的各种返回类型对应的默认返回值如下所示:

类型默认返回值
Stringnull
StringBuffernull
StringBuildernull
byte0
Byte0
char‘\u0000’
Character0
booleanfalse
BooleanBoolean.False
short0
Short0
int0
Integer0
long0L
Long0L
float0F
Float0F
double0D
Double0D
BigDecimalnull
自定义类null
List元素数量为0的LinkedList对象
Map元素数量为0的HashMap对象

可参考示例TestStMockUnstubbedMethod类。

3. 被Stub方法条件不满足的返回值

对于被Stub的方法,在执行时若参数不满足Stub条件,返回值与未被Stub的方法相同,返回各类型对应的默认值。可参考示例TestStMockStubNotSatisfied类。

4. 未Stub的方法的返回值处理分析

对静态方法所在的类进行Mock时会使用PowerMockito.mockStatic()方法。

查看PowerMockito类的“public static synchronized void mockStatic(Class<?> type, Class<?>… types)”方法,注释为“为类的所有方法启用静态Mock”。在其中调用了“DefaultMockCreator.mock(type, true, false, null, null, (Method[]) null);”方法。

DefaultMockCreator类在org.powermock.api.mockito.internal.mockcreation包中,mock()方法中调用了“MOCK_CREATOR.createMock(type, isStatic, isSpy, delegator, mockSettings, methods);”。

MOCK_CREATOR为DefaultMockCreator类的对象,在DefaultMockCreator类的createMock()方法中,调用了“doCreateMock(type, isStatic, isSpy, delegatorCandidate, mockSettings, methods);”。

在DefaultMockCreator类的doCreateMock()方法中,调用了“createMethodInvocationControl(typeToMock, methods, delegator, mockSettings);”。

在DefaultMockCreator类的createMethodInvocationControl()方法中,调用了“Mockito.mock(type, mockSettings != null ? mockSettings : Mockito.withSettings());”,mockSettings对应PowerMockito.mockStatic()调用DefaultMockCreator.mock()方法时的第5个参数mockSettings,为null,因此调用上述Mockito.mock()方法时的参数为“type, Mockito.withSettings()”。

对应Mockito类的“public static <T> T mock(Class<T> classToMock, MockSettings mockSettings)”方法,调用了“MOCKITO_CORE.mock(classToMock, mockSettings);”,mockSettings参数对应Mockito.withSettings()。

在Mockito类的withSettings()方法中,返回“new MockSettingsImpl().defaultAnswer(RETURNS_DEFAULTS);”。

MockSettingsImpl类在org.mockito.internal.creation中,实现了org.mockito.MockSettings接口,defaultAnswer()方法的注释为“指定未被stub的方法调用的默认answer,传入的参数为未被stub的方法被设置的默认answer”。

RETURNS_DEFAULTS为Mockito类中的变量,等于Answers.RETURNS_DEFAULTS。

Answers枚举中的RETURNS_DEFAULTS值为GloballyConfiguredAnswer类的对象。

GloballyConfiguredAnswer类实现了Answer接口,answer()方法返回“new GlobalConfiguration().getDefaultAnswer().answer(invocation);”。

GlobalConfiguration类的getDefaultAnswer()方法返回“GLOBAL_CONFIGURATION.get().getDefaultAnswer();”,GLOBAL_CONFIGURATION为ThreadLocal<IMockitoConfiguration>,其值通过createConfig()方法设置。在createConfig()方法中,若new ClassPathLoader().loadConfiguration()返回非空则直接使用,若返回为空则使用DefaultMockitoConfiguration对象。

在ClassPathLoader类的loadConfiguration()方法中,判断是否已加载org.mockito.configuration.MockitoConfiguration类,若未加载则返回null,由于默认不存在该类,因此默认会返回null,GlobalConfiguration类的getDefaultAnswer()方法会返回DefaultMockitoConfiguration对象,

在DefaultMockitoConfiguration类的getDefaultAnswer()方法中,返回了ReturnsEmptyValues对象。

ReturnsEmptyValues类在org.mockito.internal.stubbing.defaultanswers包中,实现了Answer接口,在其answer()方法中,对toString与compareTo方法进行了单独处理,其他情况在returnValueFor方法中处理。

在ReturnsEmptyValues类的returnValueFor()方法中,通过Primitives.isPrimitiveOrWrapper()判断若为基本类型或其包装类型,则通过Primitives.defaultValue()方法返回对应的默认值。

Primitives类在org.mockito.internal.util包中,在其Map<Class<?>, Object> PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES变量中保存了基本类型及其包装类型,以及对应的默认值,代码如下:

PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Boolean.class, false);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Character.class, '\u0000');
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Byte.class, (byte) 0);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Short.class, (short) 0);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Integer.class, 0);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Long.class, 0L);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Float.class, 0F);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(Double.class, 0D);

PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(boolean.class, false);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(char.class, '\u0000');
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(byte.class, (byte) 0);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(short.class, (short) 0);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(int.class, 0);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(long.class, 0L);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(float.class, 0F);
PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.put(double.class, 0D);

在ReturnsEmptyValues类的returnValueFor方法中,判断不是基本类型,也不是基本类型的包装类型时,处理代码如下:

if (type == Iterable.class) {
    return new ArrayList<Object>(0);
} else if (type == Collection.class) {
    return new LinkedList<Object>();
} else if (type == Set.class) {
    return new HashSet<Object>();
} else if (type == HashSet.class) {
    return new HashSet<Object>();
} else if (type == SortedSet.class) {
    return new TreeSet<Object>();
} else if (type == TreeSet.class) {
    return new TreeSet<Object>();
} else if (type == LinkedHashSet.class) {
    return new LinkedHashSet<Object>();
} else if (type == List.class) {
    return new LinkedList<Object>();
} else if (type == LinkedList.class) {
    return new LinkedList<Object>();
} else if (type == ArrayList.class) {
    return new ArrayList<Object>();
} else if (type == Map.class) {
    return new HashMap<Object, Object>();
} else if (type == HashMap.class) {
    return new HashMap<Object, Object>();
} else if (type == SortedMap.class) {
    return new TreeMap<Object, Object>();
} else if (type == TreeMap.class) {
    return new TreeMap<Object, Object>();
} else if (type == LinkedHashMap.class) {
    return new LinkedHashMap<Object, Object>();
} else if ("java.util.Optional".equals(type.getName())) {
    return JavaEightUtil.emptyOptional();
} else if ("java.util.OptionalDouble".equals(type.getName())) {
    return JavaEightUtil.emptyOptionalDouble();
} else if ("java.util.OptionalInt".equals(type.getName())) {
    return JavaEightUtil.emptyOptionalInt();
} else if ("java.util.OptionalLong".equals(type.getName())) {
    return JavaEightUtil.emptyOptionalLong();
} else if ("java.util.stream.Stream".equals(type.getName())) {
    return JavaEightUtil.emptyStream();
} else if ("java.util.stream.DoubleStream".equals(type.getName())) {
    return JavaEightUtil.emptyDoubleStream();
} else if ("java.util.stream.IntStream".equals(type.getName())) {
    return JavaEightUtil.emptyIntStream();
} else if ("java.util.stream.LongStream".equals(type.getName())) {
    return JavaEightUtil.emptyLongStream();
}

//Let's not care about the rest of collections.
return null;

总结如下:

使用PowerMockito.mockStatic()方法对类的静态方法进行Mock时,默认情况下会使用Mockito.RETURNS_DEFAULTS作为默认的Answer,对于未被Stub的方法,会返回各类型对应的默认值。

5. 对类进行Mock时设置默认Answer

PowerMockito.mockStatic()方法支持通过传入Answer或MockSettings对象设置默认的Answer,在执行被Mock类的未Stub的静态方法时,由指定的默认Answer进行处理。

当传入Answer对象时,对应PowerMockito类的方法“public static void mockStatic(Class<?> classMock, @SuppressWarnings(“rawtypes”) Answer defaultAnswer)”,示例如下:

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, new CallsRealMethods());

当传入MockSettings对象时,需要通过MockSettings defaultAnswer(Answer defaultAnswer)方法设置默认Answer,对应PowerMockito类的方法“public static void mockStatic(Class<?> classToMock, MockSettings mockSettings)”,示例如下:

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, Mockito.withSettings().defaultAnswer(new CallsRealMethods()));

当类的静态方法被Stub后,在执行该方法时受到对应的Stub控制,不再受默认Answer的影响,可参考示例TestStMockDftAnsCallsRealMethodsA1类。

5.1. 相关的类

5.1.1. Mockito类中的Answer实现类

Mockito类的成员变量包含一些Answer实现类,可作为默认Answer使用,如下所示:

  • RETURNS_DEFAULTS

参考 https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#RETURNS_DEFAULTS 。

对于方法未被Stub的被Mock的类,RETURNS_DEFAULTS是其默认的Answer。通常只返回一些空值。

该实现首先尝试使用全局配置,如果没有全局配置,则将使用返回0,空集合,null等值的默认Answer。

  • RETURNS_SMART_NULLS

参考 https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#RETURNS_SMART_NULLS 。

该实现在使用遗留代码时可能会有所帮助。未Stub的方法通常返回null。如果代码使用未stub调用返回的对象,可能会出现NullPointerException异常。该Answer实现返回SmartNull而不是null。SmartNull提供比NPE更好的异常消息,因为它指出了调用未Stub方法的代码行,只需单击堆栈跟踪就可以分析。

ReturnsSmartNulls首先尝试返回普通值( 0,空集合,空字符串等 ),然后尝试返回SmartNull。如果返回类型为final,则返回null。

ReturnSmartNulls可能会成为Mockito 4.0.0中的默认返回值策略。

  • RETURNS_MOCKS

参考 https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#RETURNS_MOCKS 。

该实现在使用遗留代码时可能会有所帮助。

ReturnMocks首先尝试返回普通值( 0,空集合,空字符串等 ),然后尝试返回Mock对象。如果返回值类型无法Mock( 如是final类型 ),则返回null。

  • RETURNS_DEEP_STUBS

参考 https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#RETURNS_DEEP_STUBS 。

常规干净的代码很少需要使用此功能,略。

  • CALLS_REAL_METHODS

参考 https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#CALLS_REAL_METHODS 。

该实现在使用遗留代码时可能会有所帮助。使用此实现时,未Stub的方法将委托给真实实现。这是一种创建部分模拟对象的方法,该对象默认情况下会调用真实方法。

  • RETURNS_SELF

参考 https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#RETURNS_SELF 。

每当调用返回等于类或超类的类型的方法时,都允许Mock构建器返回自身。

5.1.2. Answers枚举中的Answer实现类

Mockito类中的Answer实现类,均对应Answers枚举中的同名对象。

Answers枚举包含类型为Answer<Object>的变量implementation,对应Answer接口实现类,Answers枚举实现了Answer接口,在answer()方法中调用了implementation的answer()方法并返回,因此Answers的枚举值可以作为对应的Answer实现类使用,Answers枚举的枚举类型及枚举值对应的Answer实现类如下所示:

Answers枚举类型Answer实现类
RETURNS_DEFAULTSGloballyConfiguredAnswer
RETURNS_SMART_NULLSReturnsSmartNulls
RETURNS_MOCKSReturnsMocks
RETURNS_DEEP_STUBSReturnsDeepStubs
CALLS_REAL_METHODSCallsRealMethods
RETURNS_SELFTriesToReturnSelf

以上Answer实现类均在org.mockito.internal.stubbing.defaultanswers包中。

5.1.3. answers包中的Answer实现类

在org.mockito.internal.stubbing.answers包中存在一些Answer实现类,如下所示。

  • AnswersWithDelay

延迟指定的时间后,返回指定的Answer的返回值。

  • CallsRealMethods

该实现在使用遗留代码时可能会有所帮助。使用此实现时,未Stub的方法将委托给真实实现。这是一种创建部分模拟对象的方法,该对象默认情况下会调用真实方法。在调用真实方法时,通过InvocationOnMock invocation的callRealMethod()方法实现。

  • ClonesArguments

注释中说明为TODO,略。

  • DoesNothing

该实现什么也不做,在answer()方法中返回null。该实现不支持通过new创建实例,需要使用doesNothing()方法获得实例。

  • Returns

Returns类在构造时需要传入一个用户指定的对象Object value,在answer()方法中会返回value对象。

Mockito.when()方法的返回类型为OngoingStubbing接口,BaseStubbing类实现了OngoingStubbing接口。

在BaseStubbing类的thenReturn()方法中,返回“thenAnswer(new Returns(value));”,使用了Returns类。

  • ReturnsArgumentAt

返回传递参数中指定下标的参数值。argumentIndex表示调用的参数数组中的索引。如果此数字等于-1,则返回最后一个参数。

  • ReturnsElementsOf

返回集合的元素。永远返回最后一个元素。当需要返回元素集合时,该功能可能会很有用。

  • ThrowsException

总是抛出相同的Throwable对象的Answer实现类。

5.2. 执行真实方法

使用Mockito.CALLS_REAL_METHODS、Answers.CALLS_REAL_METHODS、CallsRealMethods等作为默认Answer,可以使被Mock的静态方法所在的类的未被Stub的方法默认执行真实方法。在调用PowerMockito.mockStatic()方法时,可以直接使用以上Answer,或使用Mockito.withSettings().defaultAnswer()获得默认Answer为以上指定Answer的MockSettings。

示例如下,可参考示例TestStMockDftAnsCallsRealMethodsA1、TestStMockDftAnsCallsRealMethodsA2、TestStMockDftAnsCallsRealMethodsA3、TestStMockDftAnsCallsRealMethodsWS1、TestStMockDftAnsCallsRealMethodsWS2、TestStMockDftAnsCallsRealMethodsWS3类。

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, Mockito.CALLS_REAL_METHODS);
PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, Answers.CALLS_REAL_METHODS);
PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, new CallsRealMethods());

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, Mockito.withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));
PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, Mockito.withSettings().defaultAnswer(new CallsRealMethods()));

5.3. 抛出异常

使用ThrowsException作为默认Answer,可以使被Mock的静态方法所在的类的未被Stub的方法默认抛出指定异常,ThrowsException在创建时需要指定需要抛出的异常对象,如下所示,可参考示例TestStMockDftAnsThrowsExpt类。

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, new ThrowsException(new RuntimeException(TestConstants.MOCKED)));

5.4. 什么也不做

使用DoesNothing作为默认Answer,可以使被Mock的静态方法所在的类的未被Stub的方法什么也不做,DoesNothing需要使用doesNothing()方法返回对象实例,如下所示:

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, DoesNothing.doesNothing());

使用DoesNothing作为默认Answer,不同类型的返回值,除了数字相关基本类型返回0,boolean返回false外,其他类型均返回null,如下所示:

返回类型返回值
Stringnull
StringBuffernull
StringBuildernull
byte0
Bytenull
char‘\u0000’
Characternull
booleanfalse
Booleannull
short0
Shortnull
int0
Integernull
long0L
Longnull
float0F
Floatnull
double0D
Doublenull
BigDecimalnull
自定义类null
Listnull
Mapnull

可参考示例TestStMockDftAnsDoesNothing类。

6. Mockito.when()操作导致真实方法被执行或抛出异常

以下针对静态公有非void方法进行分析(对于静态方法,Mock.when().then…()不支持公有非void之外的方法)。

参考“CALLS_REAL_METHODS”( https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#CALLS_REAL_METHODS )。使用when(mock.getSomething()).thenReturn(fakeValue)语法进行Stub会执行真实方法,建议使用doReturn语法。

在对类执行PowerMockito.mockStatic()操作时,若默认Answer指定为执行真实方法,当使用Mockito.when().then…()方法执行Stub时,会执行真实方法。如以下示例中,执行Mockito.when(TestStaticPublicNonVoid2.testString())方法时,真实方法会执行,可参考示例TestStMockSECallsRealMethods类。

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, new CallsRealMethods());

Mockito.when(TestStaticPublicNonVoid2.testString(Mockito.anyString())).thenReturn(TestConstants.FLAG1);

在对类执行PowerMockito.mockStatic()操作时,若默认Answer指定为抛出异常,当使用Mockito.when().then…()方法执行Stub时,会抛出指定的异常。如以下示例中,执行Mockito.when(TestStaticPublicNonVoid2.testString())方法会抛出异常RuntimeException,可参考示例TestStMockSEThrowsExpt类。

PowerMockito.mockStatic(TestStaticPublicNonVoid2.class, new ThrowsException(new RuntimeException(TestConstants.MOCKED)));

Mockito.when(TestStaticPublicNonVoid2.testString(Mockito.anyString())).thenReturn(TestConstants.FLAG1);

6.1. Mockito.when()操作执行真实方法或抛出异常的原因分析

使用Mockito.when().then…()对静态公有非void方法进行Stub时,可以分解为以下三步:

  • 执行原始方法,参数使用Stub条件,获取返回值;

  • 针对返回值执行Mockito.when()方法,获得OngoingStubbing对象

  • 执行OngoingStubbing的then…()方法,设置Stub操作

例如对静态方法TestStaticPublicNonVoid2.testString()进行Stub,当参数为任意字符串时,返回字符串TestConstants.FLAG1对应的代码可以分解为以下步骤:

// 分解前
Mockito.when(TestStaticPublicNonVoid2.testString(Mockito.anyString())).thenReturn(TestConstants.FLAG1);

// 分解后

// 执行原始方法
String str = TestStaticPublicNonVoid2.testString(Mockito.anyString());

// 执行Mockito.when()方法,获得OngoingStubbing对象
OngoingStubbing ongoingStubbing = Mockito.when(str);

// 执行then...()方法,设置Stub操作
ongoingStubbing.thenReturn(TestConstants.FLAG2);

当执行PowerMockito.mockStatic方法指定默认Answer为执行真实方法时,以上执行原始方法的步骤会执行真实方法,可参考示例TestStMockSECallsRealMethods类;

当执行PowerMockito.mockStatic方法指定默认Answer抛出异常时,以上执行原始方法的步骤会抛出异常,可参考示例TestStMockSEThrowsExpt类;

当执行PowerMockito.mockStatic方法指定默认Answer为默认的返回空值的Answer时,以上执行原始方法的步骤不会执行真实方法,可参考示例TestStMockSEReturnsDefaults类;

当执行PowerMockito.mockStatic方法指定默认Answer什么也不做时,以上执行原始方法的步骤不会执行真实方法,可参考示例TestStMockSEDoesNothing类。

可以看到,Mockito.when()操作执行真实方法或抛出异常的原因,是Mockito.when()方法中指定的原始方法会被执行,有可能确实执行真实方法,或抛出异常。

6.2. 避免Stub操作执行真实方法或抛出异常

PowerMockito.do…().when()方法与Mockito.when().then…()方法功能类似,使用PowerMockito.do…().when()方法进行Stub时,不会执行真实方法,在有需要时可以使用PowerMockito.do…().when()方法替代Mockito.when().then…()方法进行Stub。

对静态方法使用PowerMockito.do…().when()方法进行Stub的语法为“PowerMockito.do…().when(静态方法所在的类.class, 静态方法名, Stub参数条件)”,示例如下:

PowerMockito.doReturn(TestConstants.MOCKED).when(TestStaticPublicNonVoid2.class, "testString", TestConstants.FLAG1);

Mockito.when().then…()方法及对应的PowerMockito.do…().when()方法如下所示:

then…()方法对应的do…()方法
Mockito.when().thenReturn()PowerMockito.doReturn().when()
Mockito.when().thenThrow()PowerMockito.doThrow().when()
Mockito.when().thenAnswer()PowerMockito.doAnswer().when()
Mockito.when().thenCallRealMethod()PowerMockito.doCallRealMethod().when()

可参考示例TestStMockSEThrowsExpt、TestStMockSECallsRealMethods类。

若使用PowerMockito.when(静态方法所在的类.class, 静态方法名, Stub参数条件).then…()方法进行Stub,无法避免执行真实方法或抛出异常,因为PowerMockito.when()方法中会调用“Mockito.when(Whitebox.<T>invokeMethod(clazz, methodToExpect, arguments))”,“Whitebox.<T>invokeMethod”方法会执行真实方法。

Mockito单元测试实战:从核心概念到复杂场景的Java测试指南 单元测试是软件工程中确保代码质量的基础实践,其核心原理在于隔离被测单元与外部依赖,实现快速、独立的验证。通过模拟(Mocking)技术,开发者可以创建虚拟对象替代真实依赖,从而聚焦业务逻辑本身,提升测试的稳定性和执行效率。这一技术价值在微服务、持续集成等现代工程实践中尤为突出,广泛应用于数据库交互、第三方API调用、文件系统操作等需要隔离的测试场景。本文以Mockito框架为例,深入解析其Mock对象、Stub打桩、Spy间谍等核心机制,并结合参数匹配器、行为验证等实战技巧,系统讲解如何应对静态方法、voi 阅读详情

相关推荐

Java单元测试Mockito实战:从核心概念到Spring集成完整指南

在Java单元测试中,依赖外部组件(如数据库、网络服务)会导致测试复杂、缓慢且不稳定。为了解决这一问题,模拟(Mock)技术应运而生,其核心原理是通过创建虚拟对象来替代真实依赖,从而实现对被测代码的隔离测试。这种技术能显著提升测试执行速度与可靠性,是构建高质量软件的关键实践。Mockito作为Java领域最流行的模拟框架,通过简洁的API提供了强大的模拟与打桩能力,广泛应用于各种业务场景,特别是微服务架构下的组件测试。本文以Mockito为核心,系统讲解其核心概念(Mock、Stub、Spy)、行为模拟、交

weixin_30335353的博客 342

Java单元测试实战:Mockito与JUnit 5核心用法与最佳实践

单元测试是软件工程中验证代码逻辑正确性的基础实践,其核心价值在于快速、独立地验证代码单元。在Java生态中,JUnit作为事实标准的测试框架,提供了测试用例编写、生命周期管理和断言等基础能力。然而,当代码依赖外部服务、数据库或复杂对象时,传统测试会因环境依赖而变得缓慢、脆弱。Mockito作为模拟框架,通过创建模拟对象(Mock Object)来解决这一痛点,它允许开发者定义依赖对象的行为,实现测试隔离,从而提升测试速度与稳定性。Mockito与JUnit 5的深度集成,通过@ExtendWith(Mock

既是过河之卒,惟有奋力向前。 544

Java单元测试Mock技术详解:从核心原理到Mockito实战

单元测试是保障软件质量的关键环节,其核心在于对最小可测试单元进行隔离验证。在测试过程中,外部依赖如数据库、网络服务等往往不可控,导致测试脆弱且低效。Mock技术通过创建模拟对象来替代真实依赖,实现了测试目标的隔离、行为的预设控制以及执行速度的显著提升。这一技术不仅解决了外部环境干扰问题,还能轻松模拟各种异常和边界场景,是构建健壮、可维护代码体系的重要工程实践。在Java生态中,Mockito以其优雅的API和强大的验证功能成为社区事实标准,广泛应用于日常开发。本文以订单服务场景为例,深入解析如何利用Mock

weixin_30417487的博客 301

Mockito教程

Mock简单使用

Troub_cy的博客 1982

Java单元测试实战:JUnit 5与Mockito进阶应用与Spring Boot集成

单元测试是软件工程中保障代码质量的核心实践,通过隔离测试单个代码单元来验证其逻辑正确性。其原理在于模拟依赖、控制输入并断言输出,从而构建可靠的自动化验证体系。在Java生态中,JUnit作为事实标准的测试框架,与Mockito模拟库形成黄金组合,为开发者提供了强大的测试工具链。掌握JUnit 5的现代注解体系、参数化测试以及Mockito的精细打桩与验证技巧,能显著提升测试代码的可维护性与执行效率。特别是在Spring Boot等现代框架中,结合@WebMvcTest、@DataJpaTest等切片测试注解

396

Android单元测试实战:JUnit与Mockito构建可靠测试体系

单元测试是软件工程中保障代码质量的核心实践,通过隔离验证单个代码单元(如方法、类)的逻辑正确性,确保软件模块的可靠性。其原理在于使用测试框架(如JUnit)定义测试用例,并借助模拟工具(如Mockito)隔离外部依赖,从而在快速反馈的本地环境中执行验证。这一技术价值在于提升代码可维护性、减少回归缺陷,并支持持续集成流程。在Android开发场景中,单元测试尤其关键,因为移动应用常涉及复杂的状态管理和平台API调用。本文聚焦于Android环境下的单元测试实战,详细解析如何使用JUnit搭建测试骨架,并利用M

weixin_34221773的博客 620

Mockito+PowerMock单元测试常见问题与解决方案

单测所在的类需要放在test包下和被测类同目录层级下,如被测类DtsAccountService放在src/main/java 目录com.qiguliuxing.dts.db.service下,那么测试类DtsAccountServiceTest需要相应放在src/test/java 目录com.qiguliuxing.dts.db.service下.我亦无他,唯手熟尔。调整对mock方法的入参,要么同时用真实值,要么同时用模拟值,如Mockito.anyInt()、Mockito.anyLong()…

weixin_51360020的博客 3085

FPGA新手必看:XC7Z020最小系统搭建全攻略(附原理图解析)

本文为FPGA新手提供了XC7Z020最小系统搭建的完整实战指南。文章详细解析了电源架构、时钟复位、配置调试等关键硬件电路设计,并重点剖析了外围电路与端口引脚的连接要点及常见陷阱,帮助读者从零开始构建稳定可靠的开发平台。

weixin_29189377的博客 360

自动生成mock简单的测试

package com.areyoo.lok.controller; import com.areyoo.lok.vo.TestTwoVo; import java.lang.reflect.*; import java.util.HashSet; import java.util.ArrayList; import com.alibaba.fastjson.JSON; import com.areyoo.lok.service.api.WwService; import com.areyoo.lok.

erlanp的专栏 1561

win11下的MySQL安装

目前官方最新版本是8.0.26,考虑到其稳定性、可靠性还需一定周期保证,所以使用官方版求稳定仍然建议5.7系列。3、选择MySQL Servers 5.7.38 -x64,然后按绿色箭头将选中的版本移植到右边选中框中。4、点击下方蓝色Advanced Options,选择安装位置。1、在开始界面搜索MySQL,点击command line。4、在“系统变量”中选择“path”,点击编辑。5、新建——>增加MySQL路径——>确定,12、execute,安装好后next。9、不需要做修改,直接点击next。.

rensweet的博客 2万+

Voxel Hashing技术解析:如何解决TSDF内存爆炸问题?

本文深入解析Voxel Hashing技术如何有效解决TSDF内存爆炸问题。通过动态内存分配和空间哈希函数设计,该技术将内存占用降低96.6%,同时保持高精度重建。文章详细介绍了GPU加速实现、现代系统演进及实践指南,为实时3D重建提供工程解决方案。

m2n3b4v5c6的博客 715

Mockito – JAXB的RETURNS_DEEP_STUBS

抱歉,有一段时间没有写东西,但是我正忙于为DZone编写JBoss Drools Refcard,而我正在写一本关于Mockito的书,因此我没有太多时间来写博客了…… 无论如何,最近在我当前的项目中,我对使用Mockito和JAXB结构进行单元测试有一个有趣的情况。 我们已经从为我们提供的模式生成的嵌套了非常深的JAXB结构,这意味着我们无论如何都无法更改它。 让我们看一下项目结构...

最佳 Java 编程 940

Windows Server 2019/2022 RDS 授权实战:3步激活许可证服务器,解决120天宽限期问题

本文详细介绍了Windows Server 2019/2022 RDS授权实战,提供3步激活许可证服务器的完整解决方案,解决120天宽限期问题。涵盖远程桌面授权服务器配置、许可证激活方法及组策略设置,确保企业合规使用远程桌面服务。

weixin_32705179的博客 984

mockito_Mockito – JAXB的RETURNS_DEEP_STUBS

mockito 抱歉,有一段时间没有写东西,但是我正忙于为DZone编写JBoss Drools Refcard,而且我正在写一本有关Mockito的书,因此我没有太多时间来写博客了…… 无论如何,最近在我当前的项目中,我对使用Mockito和JAXB结构进行单元测试有一个有趣的情况。 我们已经从为我们提供的模式生成的嵌套了非常深的JAXB结构,这意味着我们无论如何都无法更改它。 让我们看一...

cunfeng7797的博客 321

SAP SM30数据维护实战:条件筛选与动态校验的实现技巧

本文详细介绍了SAP SM30数据维护的实战技巧,重点讲解如何通过条件筛选实现精准数据查取,以及利用表维护生成器事件实现动态数据检查与校验。文章提供了从基础视图创建到高级事件编程的完整流程,包括调用函数VIEW_MAINTENANCE_CALL传递筛选条件,以及在NEW_DATA和CHANGE_SAVE事件中编写业务规则校验逻辑,帮助开发者提升SM30的管控能力与数据质量。

q9w8e7r6t5的博客 521

基于深度学习的番茄成熟度检测系统——YOLOv5、YOLOv8、YOLOv10及UI界面的实现

YOLO是一种快速且准确的目标检测模型,近年来,YOLOv5、YOLOv8和YOLOv10作为YOLO系列的重要版本,分别在速度、精度和效率上进行了优化。下面我们简要介绍这些模型。本文介绍了如何基于YOLOv5、YOLOv8和YOLOv10等深度学习模型,结合PyQt5设计一个番茄成熟度检测系统。通过训练模型、优化算法和设计用户友好的界面,我们能够构建一个高效且准确的番茄成熟度检测系统,广泛应用于农业自动化和智能化管理中。

YOLO 1002

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

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对静态方法对应的类进

adrninistrat0r的博客 6819

【从0到1实战】C# WinForm开发工业级PLC监控系统(完整串口+Modbus RTU/TCP+数据库存储+源码+避坑指南)

做C#工控上位机开发的工程师,尤其是刚入行的新人,最核心的刚需就是开发一套完整的PLC监控系统。这也是工控领域最基础、最核心、应用最广的项目类型——小到单台PLC的设备测控,大到整线的产线监控,本质都是「上位机与PLC通讯,实现数据采集、参数下发、状态监控、数据存储」。碎片化的知识点学了很多,串口会用了、Modbus协议看了、数据库也懂点,但是始终无法把这些知识点串联起来,做出一套能落地的工业级PLC监控系统。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1561

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

Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Answer与未Stub的Spring组件方法 1.1. 未Stub的方法的返回值 对于Spring的@Component组件的Mock对象未Stub的方法,返回值为返回类型对应的默认值。与未Stub的静态方法的返回值情况类似。可参考示例TestSpMockUnstubbedMethod1类。 1.2. 未Stub的方法

adrninistrat0r的博客 1060

KNN算法

其原理是在给定的数据集中,根据某个距离度量方法,将测试数据与已知数据集中的所有数据进行距离计算,然后选取K个距离最近的数据作为测试数据的邻居,根据邻居的类别进行投票,将测试数据分类到得票最多的类别中。总之,KNN算法是一种简单而有效的分类方法,它不需要对数据进行训练,可以适用于多种数据类型和应用场景,并且可以通过调整K值或距离阈值等参数来控制算法的复杂度和性能。,KNN算法需要找到K个距离测试样本最近的训练样本,计算它们的类别,并将测试样本归入到得票最多的类别中。则取值为1,否则为0,表示邻居中属于类别。

优快云XXCQ的博客 2632

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

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

Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Spy后Stub Spring的@Component组件 Spring的@Component组件的Spy对象,未Stub的方法会执行真实方法。在使用Spy对象时,与使用原始对象效果类似。 1.1. 创建Spy对象 创建Spy对象时,可以使用Mockito.spy()方法或@Spy注解,如下所示: Mockito.spy(

adrninistrat0r的博客 2130

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Mockito核心API详解:从基础概念到高级场景的单元测试实践指南

在Java单元测试领域,Mock框架是模拟依赖对象行为、实现隔离测试的核心工具。其原理是通过动态代理或字节码增强技术创建虚拟对象,替代真实依赖,从而让开发者能够专注于被测单元的逻辑验证。这一技术的核心价值在于提升测试的可靠性、执行速度与可维护性,广泛应用于微服务、数据访问层及复杂业务逻辑的单元测试场景。深入理解Mock框架的API设计,特别是Mockito提供的流畅接口与BDD风格,能帮助开发者精准描述交互行为,有效应对静态方法模拟、参数匹配等高级场景,并从容处理常见的“self-attaching”等字节

417

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Mockito单元测试实战:从核心原理到Spring Boot集成

单元测试是保障软件质量的关键环节,其核心在于验证代码逻辑的正确性。在Java开发中,当代码依赖外部服务或复杂模块时,直接测试会面临效率低、稳定性差的问题。Mock技术通过创建虚拟对象来模拟依赖行为,实现了测试环境的隔离,从而让开发者能够聚焦于核心逻辑验证。Mockito作为Java领域主流的Mock框架,基于动态代理机制,提供了简洁的API来创建Mock对象、定义方法行为(Stub)并验证交互。这一技术显著提升了测试的可靠性与执行速度,尤其适用于微服务架构下的服务层测试、第三方API调用模拟等场景。本文以M

weixin_33834910的博客 443

JUnit 5与Mockito完全指南:Java单元测试最佳实践与工程化落地

单元测试是软件工程中保障代码质量、提升可维护性的核心实践,其核心原理在于通过隔离和验证代码单元的行为,确保其按预期工作。在Java生态中,JUnit作为事实上的标准测试框架,与Mockito这一强大的模拟库结合,构成了现代单元测试的技术基石。JUnit 5通过模块化架构、扩展模型和丰富的注解(如@ParameterizedTest、@Nested),显著提升了测试的可读性与可维护性;而Mockito则通过模拟依赖对象,实现了测试的隔离与精准验证。这种组合的技术价值在于,它能将测试代码本身转化为高质量、可执行

weixin_34194359的博客 412

Mockito单元测试实战:从核心概念到高级应用

单元测试是软件工程中确保代码质量的核心实践,其核心原理在于隔离被测代码与外部依赖,实现快速、可靠的验证。通过模拟(Mocking)技术,开发者可以创建依赖对象的替身,精确控制其行为,从而聚焦于当前模块的逻辑验证。这一技术显著提升了测试的稳定性和执行效率,是现代持续集成和敏捷开发流程的重要支撑。在Java生态中,Mockito作为最主流的模拟框架,广泛应用于服务层、数据访问层等组件的单元测试场景。本文将以Mockito为核心,深入解析其Mock对象、Spy对象等核心概念,并结合参数匹配、行为验证等高级特性,系

weixin_33743880的博客 418

java .stub 用法_java – Mockito:如何在调用时使用stub方法运行一些代码

我想存根一个存储库类来测试另一个具有存储库的类(Holder类).存储库接口支持CRUD操作,并且有很多方法,但我对Holder类的单元测试只需要调用其中的两个.存储库界面:public interface IRepo {public void remove(String... sarr);public void add(String... sarr);//Lots of other method...

weixin_39808877的博客 339
上一篇: Java单元测试实践-06.Mock后Stub静态方法
下一篇: Java单元测试实践-09.Mockito的Stub参数条件
adrninistrat0r
博客等级 码龄18年 395粉丝 136原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值