Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
This presentation outlines our general product direction and should not be relied on in
making a purchase decision. This presentation is not subject to your license
agreement or any other agreement with SAP. SAP has no obligation to pursue any
course of business outlined in this presentation or to develop or release any
functionality mentioned in this presentation. This presentation and SAP's strategy and
possible future developments are subject to change and may be changed by SAP at
any time for any reason without notice. This document is provided without a warranty
of any kind, either express or implied, including but not limited to, the implied
warranties of merchantability, fitness for a particular purpose, or non-infringement.
SAP assumes no responsibility for errors or omissions in this document, except if
such damages were caused by SAP intentionally or grossly negligent.
Unit Testing
Write Unit Tests with BUnit
Action Validations
Action InvoicePaid
Determinations
Testing a certain entity (e.g. Action “InvoicePaid”) by calling the Service Manager’s core
service executes much coding that is not test relevant.
Thus the test result does not clearly indicate whether there is an issue in the entity or in its
environment (e.g. other determinations). For instance, a determination may overwrite changes
that are done correctly in the action that is being tested.
Unit
A unit is the smallest isolatable part of an application that can be tested.
In case of business objects (BOs), a unit is, for instance, an action, a determination
or a validation.
Unit Testing
• Testing each unit separately eases the finding of errors
• By testing only the unit but not its environment, tests are more stable
• Unit testing eases the test-driven development approach
Mock Object / (Test) Double (both terms are used synonymously in the slides)
A mock object is a replacement of a certain object that implements the original
interfaces but returns only test data.
...
“ retrieve instances IO_READ- >retrieve(…)
Return Test Instances
Return Test
Instances
…
“ modify instances IO_MODIFY->delete(…)
gv_instance_deleted=X
Return Test
Instances
A root node instance can be created using the static method “create_root” of the class
/bobf/cl_bunit, with the BO key provided
DATA(lo_root) = /bobf/cl_bunit=>create_root( zif_ci_00_customer_invoice_c=>sc_bo_key ).
BO Key
A child node instance can only be created by its parent node instance using the
“create_child” method with the child node key provided
DATA(lo_item) = lo_root->create_child( zif_ci_00_customer_invoice_c=>sc_node-item ).
To set an attribute of a node instance, the chained call of methods “attribute” and “set”
can be used.
lo_item->attribute( ‘PRICE’ )->set( 10 ).
lo_item->attribute( ‘QUANTITY’ )->set( 10 ).
It is also possible to change all attributes of a node instance using the combined
structure with only one function call. Let the combined structure of the root node be of
type “s_customer_invoice”, and there is already a method, say “set_attributes”, to fill
all the fields of such structure. The attributes of a node instance can be set by the
“update” method
DATA ls_root TYPE zci_00_s_root.
set_attributes( IMPORTING is_data = ls_root ).
lo_root->update( is_root ).
Notice the keys (instance key, parent key and root key) in the combined structure
(here is_root) should be consistent with those in the node instance (here lo_root).
Besides, using the “update” method, the values of all attributes in the node instance
will be replaced by those in the combined structure.
DATA(lo_result_det) = lo_item->execute_determination(
zif_ci_00_customer_invoice_c=>sc_determination-item-calculate_amount ).
Action Key
For simple actions or determinations, where only some attributes get changed, the
assignment DATA(lo_result…) can be omitted, since those attributes can be checked
by asserting those node instances directly. Detailed explanation about result object
and assertion will be discussed in the following slides.
Consistency validation (check) and action validation (check) need to be called with
different methods, since they have different import parameters.
A consistency validation can be called using the “execute_validation” method with the
validation key
DATA(lo_result_val_c) = lo_item->execute_validation(
zif_ci_00_customer_invoice_c=>sc_validation-item-check_item_currency_code ).
Validation Key
Validation Key
The BUnit assert object can be created by the static method “assert” of the class
/bobf/cl_bunit.
DATA(lo_assert) = /bobf/cl_bunit=>assert( ).
BUnit assertion object provides two foundamental ways to check the outcome of an
action, a determination or a validation.
If the attributes of a node are to be checked, the “node” method can be used.
lo_assert->node( lo_item )->equals( lo_item_retrieved_elsewhere ).
lo_assert->node( lo_root )->attribute( ‘TOTAL_AMOUNT’ )->less_or_equal( 100 ). “ String is used for brevity
If the users want to check whether there are any messages, failed keys or created
instances, the “result” method should be called.
lo_assert->validation_result( lo_result_val )->message(
iv_message_id = zcm_ci_00_messages=>incomplete_bill_to_party-msgid )->is_error( ).
lo_assert->validation_result( lo_result_val )->has_failed_keys( lo_root->get_keys( ) ).
lo_assert->validation_result( lo_result_val )->has_no_created_nodes( ).
If the BUnit assert object calls the “node” method with a node instance, an assert node
instance is returned. There are several methods implemented by the assert node
object. For detailed information please refer to the
source code. Here, only part of them are explained:
To check whether two node instances share the
same parent instance
lo_assert->node( lo_item_1 )->is_sibling_of( lo_item_2 ).
If only one attribute of a node instance needs to be checked, the assert value object
should be used.
The assert value object is returned by the “attribute” method of the assert node object.
For example, to check whether a root node instance has the expected payment status,
the method “equals” can be used
lo_assert->node( lo_root )->attribute( ‘PAYMENT_STATUS’ )->equals( ‘02’ ).
Determination Result
The following table lists part of the available methods for the three kinds of result
objects
Methods Action Result Determination Result Validation Result
get_failed_keys
get_messages
get_created_nodes
get_exported_data
A node set is one or more node instances with the same node key. A node set can be
obtained by the following ways
DATA(lo_set_1) = /bobf/cl_bunit_node_set=>create_with_node( lo_root_1 ). “ lo_set_1 contains lo_root_1
DATA(lo_set_2) = /bobf/cl_bunit_node_set=>create_empty( ). “ lo_set_2 contains nothing
lo_set_2->add( lo_root_2 ). “ lo_set_2 contains lo_root_2
DATA(lo_set_3) = lo_set_1->merged_with( lo_set_2 ). “ lo_set_3 contains lo_root_1 and lo_root_2
The actions, determinations and validations can be called in exactly the same way as
node object
DATA(lo_result_a) = lo_set_3->execute_action( zif_ci_00_customer_invoice_c=>sc_action-root-invoice_paid ).
ENDLOOP.