Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework example #51

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ See [EXCEL2TXT.md](docs/EXCEL2TXT.md) for more info.
## Examples and Reference

- Complete reference of classes and methods can be found in [REFERENCE.md](docs/REFERENCE.md).
- A simple example can be found in [/src/zmockup_loader_example.prog.abap](/src/zmockup_loader_example.prog.abap).
- Usage example can be found in [/src/zcl_mockup_loader_base_example.clas.abap](/src/zcl_mockup_loader_base_example.clas.abap). The class itself is an example of a base class for a larger set of tests with some convenience features (totally opinionated).
- Also see unit tests - these are the most up-to-date examples
- Have a look at the how-to section in the project [Wiki](../../wiki).
- [Gitlab CI example](https://gitlab.com/atsybulsky/ut-monitor-example) - idea is to commit UTs sources as well as SMW0 object to repo and see the **text-based diffs** (which is not possible for binary objects obviously)
Expand Down
236 changes: 236 additions & 0 deletions src/zcl_mockup_loader_base_example.clas.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
class ZCL_MOCKUP_LOADER_BASE_EXAMPLE definition
public
final
create public
for testing
duration short
risk level harmless .

public section.
" THIS CLASS IN AN EXAMPLE
" It was marked as final intentionally (to avoid occasional subclassing), real class would be not final

" To check the instaled version of the ML
constants gc_required_mockup_loader_ver type string value 'v2.2.2'.

methods constructor.
class-methods class_constructor.

protected section.

class-data:
gi_ml type ref to zif_mockup_loader, " ML instance
gi_proxy_target type ref to zif_mockup_loader_stub_dummy, " Custom mock, when needed
gi_dao_stub type ref to zif_mockup_loader_stub_dummy. " Stub instance

" This is shortcut to set up custom mock to pass calls to
class-methods _set_proxy_target
importing
ii_proxy_target type ref to zif_mockup_loader_stub_dummy.

" Connects a method to a mock
" Results in stub_factory->connect call, but needed since the stub is autocreated later
class-methods _connect
importing
iv_str type string.

" 2 methods to test any structure for ONLY and SKIP markers and report on them if found
" _has_only also returns abap_true if the marker is found -> the value can be then used in test case loop, see examples
class-methods _has_only_and_warn
importing
it_index type standard table
returning
value(rv_yes) type abap_bool.
class-methods _has_skip_and_warn
importing
it_index type standard table
returning
value(rv_yes) type abap_bool.

" A shortcut to fire a warning message
class-methods _warn
importing
i_msg type string.

private section.

class-data go_stub_factory type ref to zcl_mockup_loader_stub_factory.
class-data gt_connections type string_table.

methods _inject_db_mock.

class-methods _setup_loader.
class-methods _generate_stub.
class-methods _connect_defaults.
class-methods _count_markers
importing
it_index type standard table
iv_field type abap_compname
returning
value(rv_count) type i.
class-methods _has_marker_and_warn
importing
it_index type standard table
iv_field type abap_compname
returning
value(rv_yes) type abap_bool.

ENDCLASS.



CLASS ZCL_MOCKUP_LOADER_BASE_EXAMPLE IMPLEMENTATION.


method class_constructor.
_setup_loader( ).
_connect_defaults( ).
endmethod.


method constructor.
if gi_dao_stub is not bound. "skip if generated
_generate_stub( ).
endif.
_inject_db_mock( ).
endmethod.


method _connect.
append iv_str to gt_connections.
endmethod.


method _connect_defaults.

Check failure on line 104 in src/zcl_mockup_loader_base_example.clas.abap

View check run for this annotation

abaplint / abaplint

Empty METHOD

https://rules.abaplint.org/method_length

" Here should be connections which are common for all tested classes
" Such as settings, typical master data, etc.
" For exceptional cases these connections may be overriden in a specific test class if required

* _connect( 'get_company_code -> ./cc [bukrs = i_bukrs]' ).
* _connect( 'get_document_type -> ./doct [blart = i_doctype]' ).
* _connect( 'get_partner_vbund -> ./tradep(vbund) [partner_no = i_partner]' ).
* _connect( 'get_tax_code_conditions -> ./~taxes [tax_code = i_mwskz]' ).
* _connect( 'get_tax_type -> ./taxes(mwart) [tax_code = i_mwskz]' ).

endmethod.


method _count_markers.
field-symbols <i> type any.
field-symbols <fld> type abap_bool.

loop at it_index assigning <i>.
assign component iv_field of structure <i> to <fld>.
if sy-subrc <> 0.
return. " No field in the structure
endif.
if <fld> = abap_true.
rv_count = rv_count + 1.
endif.
endloop.
endmethod.


method _generate_stub.

data lx type ref to cx_static_check.

try.

data lo_stub_factory type ref to zcl_mockup_loader_stub_factory.
data ld_stub_intf type ref to cl_abap_refdescr.
field-symbols <c> like line of gt_connections.

ld_stub_intf ?= cl_abap_typedescr=>describe_by_data( gi_dao_stub ). " Avoid hardcoding names when possible

create object lo_stub_factory
exporting
ii_ml_instance = gi_ml
i_allow_overrides = abap_true
io_proxy_target = gi_proxy_target
i_interface_name = |{ ld_stub_intf->get_referenced_type( )->get_relative_name( ) }|.

loop at gt_connections assigning <c>.
lo_stub_factory->connect( <c> ).
endloop.

gi_dao_stub ?= lo_stub_factory->generate_stub( ).

catch zcx_mockup_loader_error into lx.
cl_abap_unit_assert=>fail( lx->get_text( ) ).
endtry.

endmethod.


method _has_marker_and_warn.

data lv_count type i.
lv_count = _count_markers(
it_index = it_index
iv_field = iv_field ).
if lv_count > 0.
_warn( |test cases has { lv_count } { iv_field } markers, please check| ).
rv_yes = abap_true.
endif.

endmethod.


method _has_only_and_warn.
rv_yes = _has_marker_and_warn(
it_index = it_index
iv_field = 'ONLY' ).
endmethod.


method _has_skip_and_warn.
rv_yes = _has_marker_and_warn(
it_index = it_index
iv_field = 'SKIP' ).
endmethod.


method _inject_db_mock.
" In real life this shoold be a global class which is a real commonly used DAO or some kind of DAO factory
" DAO = "data accessor object"
lcl_dao=>inject_instance( gi_dao_stub ).
endmethod.


method _setup_loader.

data lx type ref to cx_static_check.

try.

gi_ml = zcl_mockup_loader=>create(
i_cache_timeout = 5 " may help in case of many test classes
i_encoding = zif_mockup_loader=>encoding_utf8
i_amt_format = ' .'
i_path = 'ZMOCKUP_LOADER_EXAMPLE' ).

if gi_ml->is_redirected( ) = abap_true.
_warn( 'Redirect is ON' ).
endif.

catch zcx_mockup_loader_error into lx.
cl_abap_unit_assert=>fail( lx->get_text( ) ).
endtry.

endmethod.


method _set_proxy_target.
gi_proxy_target = ii_proxy_target.
endmethod.


method _warn.
cl_abap_unit_assert=>fail(
msg = i_msg
level = if_aunit_constants=>tolerable
quit = if_aunit_constants=>no ).
endmethod.
ENDCLASS.
123 changes: 123 additions & 0 deletions src/zcl_mockup_loader_base_example.clas.locals_imp.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
class lcl_dao definition final for testing.

Check failure on line 1 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Local class name does not match pattern ^LTCL_.+$: lcl_dao

https://rules.abaplint.org/local_class_naming
public section.
class-methods get_instance
returning
value(ri_instance) type ref to zif_mockup_loader_stub_dummy.
class-methods inject_instance
importing
ii_instance type ref to zif_mockup_loader_stub_dummy.
interfaces zif_mockup_loader_stub_dummy.

private section.
class-data mi_instance type ref to zif_mockup_loader_stub_dummy.
endclass.

class lcl_dao implementation.

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_return_2conn" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_return_w_date" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_return_by_range" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_return_w_struc_param" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_return_extract_by_date" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_export" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "tab_change" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "wrong_return" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "wrong_sift" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "gen_param_target" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "proxy_test" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "return_value" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "exists" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "return_value_w_date" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

Check failure on line 15 in src/zcl_mockup_loader_base_example.clas.locals_imp.abap

View check run for this annotation

abaplint / abaplint

Implement method "return_deep" from interface "zif_mockup_loader_stub_dummy"

https://rules.abaplint.org/implement_methods

method get_instance.
if mi_instance is not bound.
create object mi_instance type lcl_dao.
endif.
ri_instance = mi_instance.
endmethod.

method inject_instance.
mi_instance = ii_instance.
endmethod.

method zif_mockup_loader_stub_dummy~tab_return.
" Real selects here ...
select * from sflight into table r_tab where connid = i_connid.
endmethod.

endclass.

**********************************************************************
* SINGLETON SETTINGS CLASS (a sample way to get test env indicator)
**********************************************************************
class lcl_context definition final create private.

public section.
data a_carrid type sflight-carrid read-only. " Indicates execution in test environment
data a_testenv type abap_bool read-only.

class-methods get_instance
returning value(ro_instance) type ref to lcl_context.

methods set_carrid
importing i_carrid type sflight-carrid.

private section.
class-data go_instance type ref to lcl_context. " Some settings for the production code

endclass.

class lcl_context implementation.
method get_instance. " Get sinleton instance
if go_instance is not bound.
create object go_instance.
endif.
ro_instance = go_instance.
endmethod.

method set_carrid. " Setup context for production environment
clear: me->a_carrid, me->a_testenv.
me->a_carrid = i_carrid.
if i_carrid = 'ZZZ'. " Special test env airline - non existing !
me->a_testenv = abap_true.
endif.
endmethod.

endclass.

**********************************************************************
* SOME BUSINESS LOGIC CLASS - the object to test
**********************************************************************
class lcl_main_logic definition final create public.

public section.
methods constructor.
methods get_price
importing
i_connid type sflight-connid
i_date type sflight-fldate
returning value(r_price) type sflight-price
exceptions not_found.

private section.
data o_context type ref to lcl_context.

endclass.

class lcl_main_logic implementation.
method constructor.
o_context = lcl_context=>get_instance( ). " Get context
endmethod.

method get_price. " Get price of the connection in the context airline
data ls_flight type sflight.

if o_context->a_testenv = abap_false. " Production env
select single price into corresponding fields of ls_flight
from sflight
where carrid = o_context->a_carrid
and connid = i_connid
and fldate = i_date.
else. " Test env
zcl_mockup_loader_store=>retrieve(
exporting
i_name = 'SFLIGHT'
i_sift = i_connid
importing
e_data = ls_flight
exceptions others = 4 ).
endif.

if sy-subrc is not initial. " Selection error ?
raise not_found.
endif.

r_price = ls_flight-price.

endmethod.
endclass.
Loading
Loading