when(mock.callMethodWithException(any())).thenThrow(new RuntimeException(“mock throw exception”), new IllegalArgumentException(“test illegal argument”));
Assertions.assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> mock.callMethodWithException(“first invoke”))
.withMessage(“mock throw exception”);
Assertions.assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> mock.callMethodWithException(“second invoke”))
.withMessage(“test illegal argument”)
.withNoCause();
doAnswer((Answer) invocation -> {
Object[] args = invocation.getArguments();
MockTarget mock1 = (MockTarget) invocation.getMock();
return "mock sayHello " + args[0];
}).when(mock).sayHello(“doAnswer”);
assertEquals(mock.sayHello(“doAnswer”), “mock sayHello doAnswer”);
// 1.doNothing, 2. throw RuntimeException
doNothing().doThrow(RuntimeException.class).when(mock).soSth();
mock.soSth();
Assertions.assertThatExceptionOfType(RuntimeException.class).isThrownBy(mock::soSth);
}
verify
用于验证某个方法是否被调用,包括可以验证该方法被调用的次数,以及等待异步方法调用完成等特性。
常用句式 verify(mockObject [, times(n) ] ).targetMethod
@Test
public void testVerifyInteractions() {
// mock creation
List mockedList = mock(List.class);
mockedList.clear();
// only clear() invoked
verify(mockedList, only()).clear();
verifyNoMoreInteractions(mockedList);
// 此处不会抛异常,因为是mock的list对象,非实际list对象
when(mockedList.get(1)).thenReturn(“two”);
assertEquals(mockedList.get(1), “two”);
// using mock object - it does not throw any “unexpected interaction” exception
mockedList.add(“one”);
// selective, explicit, highly readable verification
verify(mockedList).add(“one”);
verify(mockedList, times(1)).clear();
verify(mockedList, atLeastOnce()).add(“one”);
verify(mockedList, atMostOnce()).add(“one”);
verify(mockedList, atMost(1)).add(“one”);
verify(mockedList, atLeast(1)).add(“one”);
verify(mockedList, never()).add(“never”);
}
verify 之 after 与 timeout
针对异步调用,我们可以通过 after 或 timeout 等待一定时间,来校验目标方法是否有调用,以及在此之后获取目标方法的返回值,作进一步逻辑校验
-
after 会阻塞等满时间之后再往下执行,是固定等待多长时间的语义
-
timeout 在等待期内,拿到结果后立即向下执行,不做多余等待;是最多等待多长时间的语义
@Test
public void testAfterAndTimeout() throws Exception {
MockTarget mock = mockTarget;
doCallRealMethod().when(mock).callMethodWait(anyLong());
final long timeout = 500L;
final long delta = 100L;
// 异步调用
CompletableFuture async = CompletableFuture.runAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(timeout);
} catch (InterruptedException ignored) {
}
mock.sayHello();
mock.callMethod(“test”);
mock.callMethod(“test”);
});
// timeout() exits immediately with success when verification passes
// verify(mock, description(“invoke not yet, This will print on failure”)).callMethod(“test”);
verify(mock, timeout(timeout + delta).times(2)).callMethod(“test”);
// immediately success
verify(mock, timeout(10)).sayHello();
async.get();
// after() awaits full duration to check if verification passes
verify(mock, after(10).times(2)).callMethod(“test”);
verify(mock, after(10)).sayHello();
}
spy
spy 的官方定义是:
partial mocking, real methods are invoked but still can be verified and stubbed
会调用被 spy 的真实对象的方法,但仍能被 Mockiton 所直接用于 mock 和 verify,也就是说在没有配置 mock 行为的情况下默认是调用被 mock 对象的真实方法。
-
句式 doXxx…when 当同一目标方法上定义了多个 mock 行为,后序 mock 可以覆盖前序 mock
-
clearInvocations 仅清理之前的调用
-
reset 会重置为初始状态(所有中途的赋值都会被清理掉)
@Test
public void testDoReturn() {
// real creation
List list = new LinkedList();
List spy = spy(list);
//optionally, you can stub out some methods:
int mockSize = 100;
when(spy.size()).thenReturn(mockSize);
//size() method was stubbed - 100 is printed
assertEquals(spy.size(), mockSize);
// Overriding a previous exception-stubbing:
when(spy.size()).thenThrow(new IllegalStateException(“not init”));
doReturn(mockSize).when(spy).size();
assertEquals(spy.size(), mockSize);
//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
Assertions.assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> spy.get(0));
doReturn(“mock data”).when(spy).get(1);
//using the spy calls real methods
spy.add(“one”);
assertEquals(spy.get(0), “one”);
/*
Use this method in order to only clear invocations, when stubbing is non-trivial. Use-cases can be:
You are using a dependency injection framework to inject your mocks.
The mock is used in a stateful scenario. For example a class is Singleton which depends on your mock.
Try to avoid this method at all costs. Only clear invocations if you are unable to efficiently test your program.
*/
clearInvocations(spy);
verify(spy, times(0)).add(“two”);
reset(spy);
when(spy.size()).thenReturn(0);
assertEquals(spy.size(), 0);
}
▐ PowerMock
以上介绍的是 Mockiton 中常用的API,而 PowerMock 则更强大,可以 mock static 方法,private 方法,final 方法,enum,构造函数调用等。
示例代码中用到的测试类如下:
public enum TypeEnum {
Y(“TRUE”),
N(“FALSE”);
private final String title;
TypeEnum(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
public final class FinalTarget {
public FinalTarget() { }
public final String finalMethod() {
return “Hello final!”;
}
}
public class StaticTarget {
public static String firstMethod(String name) {
return “Hello " + name + " !”;
}
public static String secondMethod() {
return “Hello no one!”;
}
}
public class PartialTarget {
private String arg;
public PartialTarget(String arg) {
this.arg = arg;
}
public PartialTarget() { }
public String getArg() {
return arg;
}
private String privateWithArg(String arg) {
return "Hello privateWithArg! " + arg;
}
public String privateMethodCaller(String arg) {
return privateWithArg(arg) + " privateMethodCall.";
}
}
类注解
在使用 PowerMockito mock static , private , final , enum , constructor 之前需要在测试类上加入如下注解:
@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticTarget.class, PartialTarget.class, TypeEnum.class, FinalTarget.class})
static
PowerMockito.mockStatic 声明了要 mock static 方法的类
PowerMockito.mockStatic(StaticTarget.class);
StaticTarget.firstMethod(“xxx”);
verify
值得注意的是,它的 verify 方法使用比 Mockiton 更复杂。
需要先声明一下验证目标类的静态方法再紧接着调用一下,表示待验证的目标方法
PowerMockito.verifyStatic(StaticTarget.class); // 1
StaticTarget.firstMethod(invokeParam); // 2
也有类似于 Mockiton 的调用次数校验:
PowerMockito.verifyStatic(StaticTarget.class, times(1));
PowerMockito.verifyStatic(StaticTarget.class, Mockito.atLeastOnce());
private
PowerMock 模拟 private 方法 “privateWithArg” 的返回值并校验 “privateWithArg” 被调用的次数
PartialTarget partialMock = PowerMockito.mock(PartialTarget.class);
doCallRealMethod().when(partialMock).privateMethodCaller(anyString());
PowerMockito.doReturn(“mockResult”).when(partialMock, “privateWithArg”, any());
// privateMethodCaller will invoke method privateWithArg
String result = partialMock.privateMethodCaller(“arg”);
Assert.assertEquals(result, “mockResult privateMethodCall.”);
PowerMockito.verifyPrivate(partialMock, times(1)).invoke(“privateWithArg”, “arg”);
final
PowerMock 校验 mock final方法
FinalTarget finalTarget = PowerMockito.mock(FinalTarget.class);
String finalReturn = “finalReturn”;
PowerMockito.when(finalTarget.finalMethod()).thenReturn(finalReturn);
Assert.assertThat(finalTarget.finalMethod(), is(finalReturn));
enum
PowerMock mock enum,这里的 Whitebox.setInternalState 可以设置 TypeEnum fieldName=N 的值为给定的 mock 枚举
String mockValue = “mock title”;
TypeEnum typeMock = PowerMockito.mock(TypeEnum.class);
Whitebox.setInternalState(TypeEnum.class, “N”, typeMock);
when(typeMock.getTitle()).thenReturn(mockValue);
Assert.assertEquals(TypeEnum.N.getTitle(), mockValue);
Assert.assertEquals(TypeEnum.Y.getTitle(), “TRUE”);
constructor
构造器 mock 与 verify
String arg = “special arg”;
PartialTarget partialWithArgSpy = PowerMockito.spy(new PartialTarget(arg));
whenNew(PartialTarget.class).withNoArguments().thenReturn(partialWithArgSpy);
PartialTarget partialNoArg = new PartialTarget();
Assert.assertEquals(partialNoArg.getArg(), arg);
verifyNew(PartialTarget.class).withNoArguments();
完整示例如下:
import org.assertj.core.api.Assertions;
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;
import org.powermock.reflect.Whitebox;
import static org.hamcrest.core.Is.is;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.powermock.api.mockito.PowerMockito.doCallRealMethod;
import static org.powermock.api.mockito.PowerMockito.verifyNew;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数软件测试工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
深知大多数软件测试工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-OFL1sDHO-1712753389336)]
[外链图片转存中…(img-XWYOjHlJ-1712753389337)]
[外链图片转存中…(img-lONFPoCN-1712753389337)]
[外链图片转存中…(img-u2pEbHzC-1712753389338)]
[外链图片转存中…(img-NnnY0CUj-1712753389338)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-Ww187zjW-1712753389338)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!