使用ABAP实现Mock测试工具Mockito
What is Mockito?
Mockito is a mocking framework, JAVA-based library that is used for effective unit testing of JAVA applications. In our unit test there are usually some dependency on other external service implementation for example network or database service. Usually in order to isolate our test code from these dependencies we have to create mock class against them.
Mockito in Java can create transient mock class ( which is only available in current test session ) for us in a very easy way. See one example below:
This is a very simple class for book manager. Three books are hard coded. If requested book index is bigger than 3, then message 1 “not exist” returns.
In this blog, I will first introduce how Mockito is used in Java to mock this manager class, then show you how the logic of Mockito could be implemented in ABAP.
class BookManager{
private String[] books = {"Inside Java", "Inside ABAP", "Inside JavaScript"};
public String getBook(int index){
if( index < books.length)
return books[index];
return "not exist";
}
}
Use Mockito in Java
The magic is located in line 18 ~ 23. First in line 18 a proxy class is generated based on BookManager which is to be mocked, then line 20~23 we told the Mockito “when the method getBook with specified argument ( 0, 1, 2, 3 ) are called, please return given mocked data “mocked book {index}” accordingly.
And no doubt we can get the following output in console:
mocked book 0
mocked book 1
mocked book 2
mocked book 3
How does it work in Java
Now let me unveil the mistery for you. In order to make the logic better understood, I split the one line
"when(mockedManager.getBook(0)).thenReturn("mocked book 0");"
into the following equivalence:
The mock process actually consists of four steps:
Step1: create a proxy class by inheriting BookManager.class dynamically. The generated class is a sub class of BookManager created via CGLIB, which I have already demonstrate how to implement it in ABAP in this blog:
Step2: mockedManager.getBook(0): Since we call getBook on the mocked class, the original implementation of this method can never be called again. When you click F5 to debug into this method, you can find the method call of getBook is intercepted into Mockito framework code:
Inside handler.handle(invocation) in line 47, first an instance of OngoingStubbingImpl is created for later usage.
In line 93, Mockito will check whether there is available mocked data ( In Mockito the terminology for “mocked data” is “answer” ) for current metod call in method findAnswerFor. If available, go to IF branch in line 97 to return mocked data, or else return default answer, in my example I don’t prepare any mocked data for getBook, so it simply returns null.
The logic of this step could be described in the following activity diagram:
Step3: Object stubbing = when(“dummy, any string here is ok”);
OngoingStubbingImpl stub = (OngoingStubbingImpl)stubbing; The static method call simply returns the OngoingStubbingImpl instance created in step2. We need call corresponding method of this instance to feed mocked data.
Step4: stub.thenReturn(“Mocked book!!!”); This line feeds the mocked data “Mocked book!!!” for method getBook. The answer is inserted to a ConcurrentLinkedQueue.
Now the mocked data is ready for consuming in line
System.out.println(mockedManager.getBook(0));
Since all the previous four steps for mock are done, we expect this time, the findAnswerfor will really return something.
Inside this method, each element in the queue is looped to evaluate whether it matches the mocked method call:
The evaluation is done based on three conditions: mocked class instance must be equal, method name and argument must be equal.
finally mocked data is returned for getBook in this IF branch.
How to simulate Mockito in ABAP
First this is the book manager class written in ABAP:
class ZCL_BOOK_MANAGER definition
public
create public .
public section.
methods CONSTRUCTOR .
methods GET_BOOK
importing
!IV_INDEX type I
returning
value(RV_BOOK_NAME) type STRING .
protected section.
private section.
data MT_BOOKS type STRING_TABLE .
ENDCLASS.
CLASS ZCL_BOOK_MANAGER IMPLEMENTATION.
METHOD constructor.
mt_books = VALUE string_table( ( CONV #('Inside Java') )
( CONV #( 'Inside ABAP' ) )
( CONV #( 'Inside Javascript' ) ) ).
ENDMETHOD.
method GET_BOOK.
rv_book_name = value #( mt_books[ iv_index ] DEFAULT 'not exist' ).
endmethod.
ENDCLASS.
And this is the report to test:
REPORT zmockito1.
DATA(lo_stub) = zcl_abap_mockito=>mock( 'ZCL_BOOK_MANAGER' ).
CHECK lo_stub IS NOT INITIAL.
DATA(lo_mock) = CAST zcl_book_manager( lo_stub ).
zcl_abap_mockito=>when( lo_mock->get_book( 1 ) )->then_return( 'Data 1' ).
zcl_abap_mockito=>when( lo_mock->get_book( 2 ) )->then_return( 'Data 2' ).
zcl_abap_mockito=>when( lo_mock->get_book( 3 ) )->then_return( 'Data 3' ).
zcl_abap_mockito=>when( lo_mock->get_book( 4 ) )->then_return( 'Data 4' ).
WRITE: / lo_mock->get_book( 1 ).
WRITE: / lo_mock->get_book( 2 ).
WRITE: / lo_mock->get_book( 3 ).
WRITE: / lo_mock->get_book( 4 ).
Execution result:
Still I will explain how the mock is done in ABAP via the same four steps as in Java Mockito.
Step1: Create a transient sub class dynamically via ABAP call:
zcl_abap_mockito=>mock
The implementation has already been explained in this blog: Implement CGLIB in ABAP
Step2:
lo_mock->get_book( 1 )
When the get_book is executed, of course the original implementation will never be called again. Instead, the mocked class will delegate this call to Mockito framework method zcl_abap_mockito=>get_mocked_data
In zcl_abap_mockito=>get_mocked_data, just the same as Java, there is a IF branch:
Step3: call method when to return the instance which is the counterpart for “OngoingStubbingImpl” in Java.
Step4: call method then_return( ‘Data 1’ ) to feed mocked data for get_book method.
Further reading
I have written a series of blogs which compare the language feature among ABAP, JavaScript and Java. You can find a list of them below:
- Lazy Loading, Singleton and Bridge design pattern in JavaScript and in ABAP
- Functional programming – Simulate Curry in ABAP
- Functional Programming – Try Reduce in JavaScript and in ABAP
- Simulate Mockito in ABAP
- A simulation of Java Spring dependency injection annotation @Inject in ABAP
- Singleton bypass – ABAP and Java
- Weak reference in ABAP and Java
- Fibonacci Sequence in ES5, ES6 and ABAP
- Java byte code and ABAP Load
- How to write a correct program rejected by compiler: Exception handling in Java and in ABAP
- An small example to learn Garbage collection in Java and in ABAP
- String Template in ABAP, ES6, Angular and React
- Try to access static private attribute via ABAP RTTI and Java Reflection
- Local class in ABAP, Java and JavaScript
- Integer in ABAP, Java and JavaScript
- Covariance in Java and simulation in ABAP
- Various Proxy Design Pattern implementation variants in Java and ABAP
- 不规则图形的碰撞检测
- 自学WP7第一个例子:时钟
- 教您最简单粗暴的MATLAB入门级爬虫2
- 前台JS(Jquery)调用后台方法 无刷新级联菜单示例
- 项目中对图片的缩放和水印效果
- 照虎画猫写自己的Spring——自定义注解
- 数据分析进阶课程笔记(六)
- 微信发布重磅更新!上线小游戏,小程序间可快速切换
- 鼠标点击层以外的地方层隐藏
- WCF后续之旅(11): 关于并发、回调的线程关联性(Thread Affinity)
- WCF后续之旅(11): 关于并发、回调的线程关联性(Thread Affinity)
- 解决文本框在updatepanel中得到焦点,输入法不能切换到中文的问题
- 得到真实外网IP、IP所在国家、省份、地区
- 机器学习在智能制造中的应用!
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 一篇文章上手Vue3中新增的API
- 先电OpenStack卸载脚本
- 先电OpenStack之neutron-vlan脚本
- 【7】进大厂必须掌握的面试题-Java面试-Jsp
- HTML5+JS 可交互360°&柱状全景图浏览
- Spring编译源代码解决spring-core缺少cglib和objenesis的jar包的办法
- 尤大 3 天前发在 GitHub 上的 vue-lit 是啥?
- CSS3旋转实例学习(附3D旋转实例)
- 学会23个linux常用命令,不做前端切图仔~
- Python新手之pycharm调试指南
- 【设计模式系列】行为型之状态模式
- PHP运行模式
- 马上2021年了线性表你还不知道原理?给老王整的明明白白
- 分治-芯片测试问题
- 你说啥什么?注解你还不会?