既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
Mock 可以交给用户
在有些情况下,某种原因你需要允许一些外部来源访问你的测试系统,像合作伙伴或者客户。这些原因导致别人也可以访问你的敏感信息,而你或许只是想允许访问部分测试环境。在这种情况下,如何向合作伙伴或者客户提供一个测试系统来开发或者做测试呢?最简单的就是提供一个mock,无论是来自于你的网络或者客户的网络。soapUI mock非常容易配置,他可以运行在soapUI或者作为一个war包发布到你的java服务器里面。
隔离系统
有时,你希望在没有系统其他部分的影响下测试系统单独的一部分。由于其他系统部分会给测试数据造成干扰,影响根据数据收集得到的测试结论。使用mock你可以移除掉除了需要测试部分的系统依赖的模拟。当隔离这些mocks后,mocks就变得非常简单可靠,快速可预见。这为你提供了一个移除了随机行为,有重复模式并且可以监控特殊系统的测试环境。
Mockito
介绍
Mockito 是一个简单的流行的 Mock 框架。它能够帮我们创建 Mock 对象,保持单元测试的独立性。
使用它只需要在 Maven 中添加依赖即可。
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
</dependency>
创建 Mock 对象
通过方法创建
class CreateMock {
@Before
public void setup() {
mockUserDao = mock(UserDao.class);
userService = new UserServiceImpl();
userService.setUserDao(mockUserDao);
}
}
通过注解创建
class CreateMock {
@Mock
UserDao mockUserDao;
@InjectMocks
private UserServiceImpl userService;
@Before
public void setUp() {
//初始化对象的注解
MockitoAnnotations.initMocks(this);
}
}
一个简单的例子:
package Mockito;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
import static org.mockito.Mockito.*;
public class MyTest {
@Test
public void myTest() {
/\* 创建 Mock 对象 \*/
List list = mock(List.class);
/\* 设置预期,当调用 get(0) 方法时返回 "111" \*/
when(list.get(0)).thenReturn("111");
Assert.assertEquals("asd", 1, 1);
/\* 设置后返回期望的结果 \*/
System.out.println(list.get(0));
/\* 没有设置则返回 null \*/
System.out.println(list.get(1));
/\* 对 Mock 对象设置无效 \*/
list.add("12");
list.add("123");
/\* 返回之前设置的结果 \*/
System.out.println(list.get(0));
/\* 返回 null \*/
System.out.println(list.get(1));
/\* size 大小为 0 \*/
System.out.println(list.size());
/\* 验证操作,验证 get(0) 调用了 2 次 \*/
verify(list, times(2)).get(0);
/\* 验证返回结果 \*/
String ret = (String)list.get(0);
Assert.assertEquals(ret, "111");
}
}
从上面代码能看出一般使用的步骤:
设置方法预期返回
通过 when(list.get(0)).thenReturn(“111”); 来设置当调用 list.get(0) 时返回 “111”,该方法就是 Stub,替换我们实际的操作。
验证方法调用
该方法验证 get(0) 方法调用的次数 verify(list, times(2)).get(0);,还可以设置是否调用过,调用时间等等。
验证返回值
Assert.assertEquals(ret, “111”); 方法验证 Mock 对象方法调用后的返回值是否达到预期。
Mockito 使用
设置 Mock 对象期望和返回值
/\* 表示第一次调用 someMethod() 返回 value1 第二次调用返回 value2 \*/
when(mock.someMethod()).thenReturn(value1).thenReturn(value2);
when(mock.someMethod()).thenReturn(value1, value2);
/\* 也可以设置两次 \*/
when(mock.someMethod()).thenReturn(value1);
when(mock.someMethod()).thenReturn(value2);
另外一种写法 doReturn()
/\* 表示第一次调用 someMethod() 返回 value1 第二次调用返回 value2 \*/
doReturn(value1).doReturn(value2).when(mock).someMethod();
/\* 若返回 void,则设置为 doNothing() \*/
doNothing().when(mock).someMethod();
对方法设定返回异常
/\* 当调用 someMethod() 方法时会抛出异常 \*/
when(mock.someMethod()).thenThrow(new RuntimeException());
/\* 对 void 方法设定 \*/
doThrow(new RuntimeException()).when(mock).someMethod();
参数匹配器
我们不一定要固定 Stub 调用时的参数,如 get(0)。可以通过参数匹配器来调用。
when(list.get(anyInt())).thenReturn("hello");
Mock 对象的行为验证
package Mockito;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.testng.annotations.Test;
import java.util.List;
import static org.mockito.Mockito.*;
/\*\*
\* Created by andy.wwh on 2016/7/18.
\*/
public class Behavior {
@Test
public void behaviorCheck() {
List mock1 = mock(List.class);
List mock2 = mock(List.class);
/\* 设置预期 \*/
when(mock1.get(0)).thenReturn("hello world");
when(mock1.get(1)).thenReturn("hello world");
when(mock2.get(0)).thenReturn("hello world");
mock1.get(0);
/\* 验证方法调用一次 \*/
verify(mock1).get(0);
mock1.get(0);
/\* 验证方法调用两次 \*/
verify(mock1, times(2)).get(0);
/\* 验证方法从未被调用过 \*/
verify(mock2, never()).get(0);
/\* 验证方法 100 毫秒内调用两次 \*/
verify(mock1, timeout(100).times(2)).get(anyInt());
/\* 设置方法调用顺序 \*/
InOrder inOrder = inOrder(mock1, mock2);
inOrder.verify(mock1, times(2)).get(0);
inOrder.verify(mock2, never()).get(1);
/\* 查询是否存在被调用,但未被 verify 验证的方法 \*/
verifyNoMoreInteractions(mock1, mock2);
/\* 验证 Mock 对象是否没有交发生 \*/
verifyZeroInteractions(mock1, mock2);
/\* 参数捕获器 \*/
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mock1, times(2)).get(argumentCaptor.capture());
System.out.println("argument:" + argumentCaptor.getValue());
}
}
验证调用次数
verify(mock1, timeout(100).times(2)).get(anyInt());
除了代码中的方法,Mockito 还提供了
- never() 没有被调用,相当于times(0)
- atLeast(N) 至少被调用N次
- atLeastOnce() 相当于atLeast(1)
- atMost(N) 最多被调用N次
超时验证
通过 timeout 我们可以进行验证程序执行时间是否符合规则。
方法调用顺序
Inorder 可以验证方法调用的顺序
verifyNoMoreInteractions 和 verifyZeroInteractions
verifyNoMoreInteractions:查询是否存在被调用,但未被 verify 验证的方法
verifyZeroInteractions:verifyZeroInteractions
ArgumentCaptor 参数捕获器
可在验证时对方法的参数进行捕获,最后验证捕获的参数值。如果方法有多个参数都要捕获验证,那就需要创建多个ArgumentCaptor对象处理。
Spy 对象验证
Mock 操作的全是虚拟对象。即使我们设置了 when(list.get(0)).thenReturn(1),我们调用如 size() 方法返回的还是 0。Mockito 还给我们提供了一种对真实对象操作的方法——Spy
做一个简单的比较:
package Mockito;
import org.testng.annotations.Test;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/\*\*
\* Created by andy.wwh on 2016/7/18.
\*/
public class MockObject {
@Test
public void MockTest() {
List list = mock(List.class);
when(list.get(0)).thenReturn("hello world");
System.out.println(list.get(0));
System.out.println(list.size());
}
}
package Mockito;
import org.testng.annotations.Test;
import java.util.LinkedList;
import java.util.List;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/\*\*
\* Created by andy.wwh on 2016/7/18.
\*/
public class MockObject {
@Test
public void MockTest() {
/\* 创建真实对象 \*/
List list = new LinkedList();
List spy = spy(list);
spy.add("hello");
when(spy.get(0)).thenReturn("hello world");
System.out.println(spy.get(0));
}
}
看个官网的例子:
@Test
public void spyTest() {
List list = new LinkedList();
List spy = spy(list);
// optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
// using the spy calls real methods
spy.add("one");
spy.add("two");
// prints "one" - the first element of a list
System.out.println(spy.get(0));
// size() method was stubbed - 100 is printed
System.out.println(spy.size());
// optionally, you can verify
verify(spy).add("one");
verify(spy).add("two");
}
参考:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
e());
// optionally, you can verify
verify(spy).add(“one”);
verify(spy).add(“two”);
}
---
参考:
[外链图片转存中...(img-BEPJyFPg-1715808466798)]
[外链图片转存中...(img-8oQ7npiu-1715808466799)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618631832)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**