四種ABAP單元測試隔離(test isolation)技術
Hi friends,
As far as I know test isolation is widely used in SAP internal to build unit test code, at least in my team. Test isolation in unit test means that in your production code you make use of some API(class method/Function module) which are developed by other team, and you would not like to really consume them during your unit test, since you would not accept that most red lights in your unit test report are caused by the bugs in those external API,right? Instead, you expect that the call of those external API during your unit test execution will be replaced by some dummy code written by yourself.
I will show you four different ways to achieve that.
The example comes from one productive class in my project. For simplicity reasons I don’t list unrelevant code here. The class is ZCL_DESTRUCTION_IMG_TOOL_S1.
The main logic is doing a cleanup work: loop every work list item, check whether it has some dependent object. If so, delete it.
The reason why test isolation is used in our unit test is because in method dependent_object_existed, we call an API provided by another team, and we don’t want that API to be really executed during our unit test execution. For demonstration reason, I use the following code to simulate the production code.
It means during the unit test on this class, the following code is NOT expected to be executed at all.
Approach1: test subclass instead
(1) Change the visibility of method DEPENDENT_OBJECT_EXISTED from private to protected. The idea is in this approach, we create a sub class ( a local test class) which inherits from ZCL_DESTRUCTION_IMG_TOOL_S1. Since the DEPENDENT_OBJECT_EXISTED is now protected, we have the chance to redefine it in the local test class.
The mock code is simple like below:
And the code for method start:
In this approach, actually the class being unit test are not lcl_destruction_test, instead of the original class ZCL_DESTRUCTION_IMG_TOOL_S1.
when execution comes into run method, since the subclass only redefines the very method dependent_object_existed, so the execution of the left methods are still using the code of ZCL_DESTRUCTION_IMG_TOOL_S1. That means all methods of ZCL_DESTRUCTION_IMG_TOOL_S1 except dependent_object_existed will be covered by unit test.
And when execution comes into method dependent_object_existed,since currently “me” points to the local test sub class, so the mock code will be executed, which is just what we expected.
The limitation of this approach is, if the author of class ZCL_DESTRUCTION_IMG_TOOL_S1 insists on that it should be defined as final, it is impossible to define any sub class of it.
Approach2 – interface extraction + optional argument
The idea is to extract the logic written in method dependent_object_existed and put its implementation into method dependent_object_existed of a new interface ZIF_SOC_DEPENDENCY_DETECTOR instead. Via such abstraction, the loose coupling of dependency detection call and its implementation is achieved.
Necessary change on production class ZCL_DESTRUCTION_IMG_TOOL_S2 source code:
(1) Private method dependent_object_existed can be removed now.
(2) Create a local class to implement the productive logic of dependency detection as usual:
(3) Create an optional argument of method run.
(4) In method run, if no reference is passed in for io_dep_obj_detector, the default one for production use will be called (line5).If there is indeed one dependent object detector passed in, use that one. (line7)
Also the previous method dependent_object_existed is removed; the interface method call is used instead.
(5) The unit test class also implements interface method dependent_object_existed.In unit test code, the optional parameter of method run will be filled, so that the redefined dependency detection logic implemented in interface method in unit test code will be called instead ( according to the logic in step4, line 7)
Now the possibility is given for consumers to provide their own dependency determination logic by implementing interface and filling the optional parameter of method run; however this is not what we expected in the beginning.
Signature of method run is changed, which is a non-critical change. (Adding a new optional method parameter is not an incompatible change)
In my opinion it could not be regarded as a 100% test isolation solution.
Approach3 – Dynamic detector initialization
Interface extraction is also necessary for this solution.
Necessary change on production class ZCL_DESTRUCTION_IMG_TOOL_S3’s source code:
(1) Create a local class to implement the productive logic of dependency detection just the same as approach2.
(2) Add a new static member attribute for technical name of dependency class name. Default value is local class name created in step1:
(3) Initialize the detector instance according to its name maintained in member attribute mv_detector_type_name.
Since its default value is the local class LCL_PROD_DEP_DETECTOR, so in the runtime the productive detection logic will be called.
(4) Define the unit test class as the friend of class ZCL_DESTRUCTION_IMG_TOOL_S3, so that it can alter even the private attribute mv_detector_type_name of ZCL_DESTRUCTION_IMG_TOOL_S3.
In the unit test code, just add one line( line 62 ). Now the detection logic redefined in unit test class will be called.
Approach3 is superior compared with approach2 in that no method signature change is required. Class consumer will have no chance to pass their own detection logic into class in a normal way. However, a new class member attribute is introduced, which could be not necessary in the next approach 4.
Approach4 – detector reference replacement
Similar with approach 3 to some degree.
Necessary change on production class ZCL_DESTRUCTION_IMG_TOOL_S4 source code:
(1) Implement the productive dependency detection logic in local class lcl_prod_dep_detector just the same as approach3.
(2) Initialize the productive detector instance in CONSTRUCTOR.
(3) Implement the interface method in test class.
(4) Define unit test class as friend of ZCL_DESTRUCTION_IMG_TOOL_S4.
(5) In unit test code, replace the instance of dependency detector with unit test class reference itself, so that our own logic would be called in unit test:
No new attribute or method interface change is required in this solution. This solution should be used for test isolation whenever possible.
要獲取更多Jerry的原創文章,請關注公眾號"汪子熙":
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24475491/viewspace-2708660/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ABAP和Java的單元測試Unit TestJava
- 測試一下MySQL四種隔離級別都做了什麼MySql
- vue單元測試vue test utils使用初探Vue
- ABAP和Java SpringBoot的單元測試JavaSpring Boot
- 面試問爛的 MySQL 四種隔離級別面試MySql
- 事務四種隔離級別
- 資源隔離技術之記憶體隔離記憶體
- 專案必備技術之單元測試
- 事務的四種隔離級別
- Mysql 四種事務隔離級別MySql
- SAP CDS view單元測試框架Test Double介紹View框架
- oracle事務隔離級別transaction isolation level初識Oracle
- 資料庫的四種隔離級別資料庫
- (轉)事務的四種隔離級別
- MySQL 的四種事務隔離級別MySql
- 一文掌握開源單元測試框架Google Test框架Go
- 程式碼重構與單元測試——重構1的單元測試(四)
- [轉帖]資料庫的快照隔離級別(Snapshot Isolation)資料庫
- Android自動化測試入門(四)單元測試Android
- SQL92標準四種隔離級別SQL
- 如何理解資料安全隔離技術
- 測試 之Java單元測試、Android單元測試JavaAndroid
- 單元測試:單元測試中的mockMock
- MySQL資料庫中的四種隔離級別MySql資料庫
- 翻譯:iOS Swift單元測試 從入門到精通 Unit Test和UI測試 UITestiOSSwiftUI
- mysql中read commited與repeatable read兩種隔離級別的測試MySqlMIT
- 混部之殤-論雲原生資源隔離技術之CPU隔離(一)
- SAP Hybris和Netweaver的租戶隔離(Tenant isolation)機制設計NaN
- Golang 單元測試執行 _test.go 中的某個 func 方法Golang
- 換種思路寫Mock,讓單元測試更簡單Mock
- 搞定Go單元測試(四)—— 依賴注入框架(wire)Go依賴注入框架
- 單元測試,只是測試嗎?
- 單元測試-【轉】論單元測試的重要性
- SpringBoot單元測試Spring Boot
- python 單元測試Python
- iOS 單元測試iOS
- Flutter 單元測試Flutter
- 單元測試 Convey