Java mocking 单元测试框架介绍
2017-05-02 15:18
295 查看
我需要在数据库里插入一些数据,基于这些真实的数据我才可以进行单元测试,而且每次都需要重复准备脚本,还要考虑数据的清理。
我需要启动一个Tomcat,然后通过Http Client发送请求,然后观察数据,才可以进行测试。
我需要启动Dubbo服务的提供者,因为我的类里依赖的这个服务,否则我的类没办法正常运行。
我需要依赖第三方的一个接口,因为我这个类是用来发送短信的,这样我才能验证我的短信发送时正常的。往往第三方都没有测试环境,即使有的话也不稳定,导致我不能经常进行持续集成的测试。
……
我们主要的面临的问题是,由于所依赖的组件不容易构造或者不容易获取,所以导致我们不容易写出单元测试,甚至由于觉得麻烦索性不写单元测试(悲伤),如:
HttpServletRequest必须在web容器中才能构造出来;
Dubbo服务必须有服务提供者;
依赖第三方的一个接口,如短信,支付等。http接口, webservice接口等;
JDBC中的ResultSet对象;
Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取比较复杂的对象,用一个虚拟的对象来创建以便测试的测试方法。
Mock最大的功能是帮你把单元测试的解耦,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
Mcokito框架使用:
如果方法返回值没有stub过,mockito会返回相应的默认值。如int会返回0,布尔值返回false。对于其他类型会返回null。重复stub两次,则以第二次为准。
@InjectMocks: 需要将Mock对象注入的对象;
@Captor:(参数捕获器)捕获方法参数进行验证;
@mock与@InjectMocks使用如下:
现在假设在service层有如下代码需要测试:
测试代码:
如上可以正常测试。但是将最后一行findByPhoneNumber(“110”)号码改成119酒会报错,如下:
单元测试三步骤:设置测试数据,设定预期结果,验证结果,三步通过,测试通过。
@Captor使用如下:
ArgumentCaptor的Api
argument.capture() 捕获方法参数
argument.getValue() 获取方法参数值,如果方法进行了多次调用,它将返回最后一个参数值
argument.getAllValues() 方法进行多次调用后,返回多个参数值
代码案例:
我需要启动一个Tomcat,然后通过Http Client发送请求,然后观察数据,才可以进行测试。
我需要启动Dubbo服务的提供者,因为我的类里依赖的这个服务,否则我的类没办法正常运行。
我需要依赖第三方的一个接口,因为我这个类是用来发送短信的,这样我才能验证我的短信发送时正常的。往往第三方都没有测试环境,即使有的话也不稳定,导致我不能经常进行持续集成的测试。
……
我们主要的面临的问题是,由于所依赖的组件不容易构造或者不容易获取,所以导致我们不容易写出单元测试,甚至由于觉得麻烦索性不写单元测试(悲伤),如:
HttpServletRequest必须在web容器中才能构造出来;
Dubbo服务必须有服务提供者;
依赖第三方的一个接口,如短信,支付等。http接口, webservice接口等;
JDBC中的ResultSet对象;
Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取比较复杂的对象,用一个虚拟的对象来创建以便测试的测试方法。
Mock最大的功能是帮你把单元测试的解耦,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
Mcokito框架使用:
验证行为
import static org.mockito.Mockito.*; public void once_created_mock_will_remember_all_interactions() { List<String> mockedList = mock(List.class); mockedList.add("one"); mockedList.clear(); //验证调用了add方法,并且参数为one verify(mockedList).add("one"); verify(mockedList).clear(); verify(mockedList).add("two"); }
打桩–>Stubbing
public void stubbing() { LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(0)).thenReturn("second"); System.out.println(mockedList.get(0)); //mock对象会覆盖整个被mock的对象,因此没有stub的方法只能返回默认值。 System.out.println(mockedList.get(999)); when(mockedList.get(1)).thenThrow(new RuntimeException()); System.out.println(mockedList.get(1)); }
如果方法返回值没有stub过,mockito会返回相应的默认值。如int会返回0,布尔值返回false。对于其他类型会返回null。重复stub两次,则以第二次为准。
参数匹配器
public void argument_matcher() { LinkedList mockedList = mock(LinkedList.class); //设置无论获取任何位置的值,都返回固定的一个fixed-element when(mockedList.get(anyInt())).thenReturn("fixed-element"); System.out.println(mockedList.get(999)); verify(mockedList).get(anyInt()); //自定义参数匹配器 when(mockedList.contains(argThat(isValid()))).thenReturn(true); System.out.println(mockedList.contains("custom-matcher")); System.out.println(mockedList.contains("custom-matcher2")); }
顺序调用
public void verify_invoke_in_order() { List singleMock = mock(List.class); singleMock.add("was added first"); singleMock.add("was added second"); InOrder inOrder = inOrder(singleMock); inOrder.verify(singleMock).add("was added first"); inOrder.verify(singleMock).add("was added second"); }
注解的使用
@mock:需要被Mock的对象,mock对象的方法不会再被真实调用,如果需要调用需要使用stub(打桩);@InjectMocks: 需要将Mock对象注入的对象;
@Captor:(参数捕获器)捕获方法参数进行验证;
@mock与@InjectMocks使用如下:
现在假设在service层有如下代码需要测试:
public boolean isEmployee(String phoneNumber) { if (StringUtils.isEmpty(phoneNumber)) { return false; } return userRepository.findByPhoneNumber(phoneNumber).isPresent(); }
测试代码:
@Mock private userRepository userRepository; @InjectMocks private userServiceImpl userServiceImpl; @Test public void testMock() { User user = new User(); stub(userRepository .findByPhoneNumber(anyString())) .toReturn(Optional.of(user)); userServiceImpl.isEmployee("110"); verify(userRepository,times(1)) .findByPhoneNumber("110");//findByPhoneNumber方法被调用一次 }
如上可以正常测试。但是将最后一行findByPhoneNumber(“110”)号码改成119酒会报错,如下:
单元测试三步骤:设置测试数据,设定预期结果,验证结果,三步通过,测试通过。
@Captor使用如下:
ArgumentCaptor的Api
argument.capture() 捕获方法参数
argument.getValue() 获取方法参数值,如果方法进行了多次调用,它将返回最后一个参数值
argument.getAllValues() 方法进行多次调用后,返回多个参数值
代码案例:
@Captor private ArgumentCaptor<Money> moneyCaptor; @Captor private ArgumentCaptor<User> userCaptor; verify(userMoneyService, times(1)).updateStatus( userCaptor.capture(),moneyCaptor.capture());//获取参数 assertThat(userCaptor.getValue().getRole(), is("Admin");//验证参数 assertThat(moneyCaptor.getValue(), is("15rmb"); //updateStatus方法如下 public void updateStatus(User user,Money money){ 执行方法…… }
相关文章推荐
- DDTUnit 数据驱动框架介绍及其在单元测试中的应用
- JavaScript单元测试框架介绍
- PHP单元测试框架 - PHPUnit介绍
- 推荐:一个写的相当好的介绍C++单元测试框架Google Test (gtest) 教程
- Javascript单元测试框架QUnitjs详细介绍
- 推荐:一个写的相当好的介绍C++单元测试框架Google Test (gtest) 教程
- Junit单元测试框架介绍
- Javascript单元测试框架QUnitjs详细介绍
- 轻松编写 C++ 单元测试 介绍全新单元测试框架组合: googletest 与 googlemock
- Python+Selenium框架设计篇之2-简单介绍unittest单元测试框架
- Js 单元测试框架介绍
- Junit4 单元测试框架的常用方法介绍
- 单元测试框架的基本使用介绍
- Python+selenium之简单介绍unittest单元测试框架
- javaScript的单元测试框架Unit.js介绍
- 测试单元测试javascript单元测试及框架介绍
- javaScript的单元测试框架Unit.js介绍
- EGL单元测试框架EUnit介绍
- javascript单元测试及框架介绍
- 基于spring test框架进行单元测试-框架介绍