Quantcast
Channel: ABAP Testing and Troubleshooting
Viewing all 44 articles
Browse latest View live

SAP NetWeaver AS, add-on for code vulnerability analysis for ABAP 7.5 is out!

$
0
0

With SAP NetWeaver AS, add-on for code vulnerability analysis 7.5 scanning of ABAP sources for security weaknesses became even more easy. Allowing more systems to be scanned for even more types of defects, the new release is also more flexible and now can be deployed centrally.

 

Using the new central security scan support, customers are now able to overcome the release limitations of previous releases. Using this approach, only one SAP NetWeaver AS 7.5 basis system is required. Systems containing the code to be scanned can be releases down to SAP NetWeaver AS ABAP 7.00 (for details check SAP note 2190113).

 

 

The benefit of this approach is also, that in future an upgrade of the central scan system allows to use the latest checks also for all remote system.

 

Using an update scan engine, you can now analyze BSP pages and even navigate directly into the BSP sources to fix your web applications in case of security issues.

In addition, there were additional checks like checks to identify coding with insufficient authorization checks. You can find more details on the new and revised checks in SAP Note 1921820 - SAP NetWeaver AS, add-on for code vulnerability analysis - support package planning.

 

If you want to get more details, check our new roadmap https://service.sap.com/~sapidb/011000358700000256742014E.pdf on the SAP Service Market Place (SMP).
 


Unit test mockup loader for ABAP

$
0
0

Hi Community !

 

I'd like to share a tool for unit testing me and my team have developed for our internal usage recently.

 

The tool is created to simplify data preparation/loading for SAP ABAP unit tests. In one of our projects we had to prepare much tables data for unit tests. For example, a set of content from BKPF, BSEG, BSET tables (FI document). The output to be validated is also often a table or a complex structure.

 

Data loader

 

Hard-coding all of that data was not an option - too much to code, difficult to maintain and terrible code readability. So we decided to write a tool which would get the data from TAB delimited .txt files, which, in turn, would be prepared in Excel in a convenient way. Certain objectives were set:

 

  • all the test data should be combined together in one file (zip)
  • ... and uploaded to SAP - test data should be a part of the dev package (W3MI binary object would fit)
  • loading routine should identify the file structure (fields) automatically and verify its compatibility with a target container (structure or table)
  • it should also be able to safely skip fields, missing in .txt file, if required (non strict mode) e.g. when processing structures (like FI document) with too many fields, most of which are irrelevant to a specific test.

 

Test class code would look like this:

 

...

call method o_ml->load_data " Load test data (structure) from mockup

  exporting i_obj       = 'TEST1/bkpf'

  importing e_container = ls_bkpf.

 

call method o_ml->load_data " Load test data (table) from mockup

  exporting i_obj       = 'TEST1/bseg'

            i_strict    = abap_false

  importing e_container = lt_bseg.

...

call method o_test_object->some_processing " Call to the code being tested

  exporting i_bkpf   = ls_bkpf

            it_bseg  = lt_bseg

  importing e_result = l_result.

 

assert_equals(...).

...

 

The first part of the code takes TAB delimited text file bseg.txt in TEST1 directory of ZIP file uploaded as a binary object via SMW0 transaction...

 

BUKRS BELNR GJAHR BUZEI BSCHL KOART ...

1000  10    2015  1     40    S     ...

1000  10    2015  2     50    S     ...

 

... and puts it (with proper ALPHA exits and etc) to an internal table with BSEG line type.

 

Store/Retrieve

 

Later another objective was identified: some code is quite difficult to test when it has a select in the middle. Of course, good code design would assume isolation of DB operations from business logic code, but it is not always possible. So we needed to create a way to substitute selects in code to a simple call, which would take the prepared test data instead if test environment was identified. We came up with the solution we called Store. (BTW might nicely co-work with newly announced TEST-SEAM feature).

 

Test class would prepare/load some data and then "store" it:

 

...

call method o_ml->store " Store some data with 'BKPF' label

  exporting i_name = 'BKPF'

            i_data = ls_bkpf. " One line structure

...

 

... And then "real" code is able to extract it instead of selecting from DB:

 

...

if some_test_env_indicator = abap_false. " Production environment

  " Do DB selects here

 

 

else.                                    " Test environment

  call method zcl_mockup_loader=>retrieve

    exporting i_name  = 'BKPF'

    importing e_data  = me->fi_doc_header

    exceptions others = 4.

endif.

 

 

 

if sy-subrc is not initial.

  " Data not selected -> do error handling

endif.

...

 

In case of multiple test cases it can also be convenient to load a number of table records and then filter it based on some key field, available in the working code. This option is also possible:

 

Test class:

 

...

call method o_ml->store " Store some data with 'BKPF' label

  exporting i_name   = 'BKPF'

            i_tabkey = 'BELNR'  " Key field for the stored table

            i_data   = lt_bkpf. " Table with MANY different documents

...

 

"Real" code:

 

...

if some_test_env_indicator = abap_false. " Production environment

  " Do DB selects here

else.                                    " Test environment

  call method zcl_mockup_loader=>retrieve

    exporting i_name  = 'BKPF'

              i_sift  = l_document_number " Filter key from real local variable

    importing e_data  = me->fi_doc_header  " Still a flat structure here

    exceptions others = 4.

endif.

 

if sy-subrc is not initial.

  " Data not selected -> error handling

endif.

...

 

As the final result we can perform completely dynamic unit tests in our projects, covering most of code, including DB select related code without actually accessing the database. Of course, it is not only the mockup loader which ensures that. This requires accurate design of the project code, separating DB selection and processing code. But the mockup loader and "store" functionality makes it more convenient.

 

illustration.jpg

 

Links and contributors

 

The tools is the result of work of my team including:

 

The code is freely available at our project page on github - sbcgua/mockup_loader · GitHub

 

I hope you find it useful

 

Alexander Tsybulsky

Working effectively with ABAP legacy code - ABAP Test Seams are your friend

$
0
0

Hello Community,

ABAP Test Seams are available with the latest SAP_BASIS stack, but what they are good for?

Consider you need to change some legacy code of ancient times. The code is deeply nested, mixes concerns and has no unit tests. Changing the code seems risky and you want to add at least characterisation tests. But even to add such a minimal safety net requires changes to the old stuff. It seems you stuck between a rock and a hard place.

By using ABAP TEST Seams one can replace test unfriendly behaviour of any statement within the same program. Just tag the code region in the domain part with a TEST-SEAM and inject other statements into this region. The injected code can alter variables, perform extra validations or do simply nothing.

For example you can:

  • replace the effect of an authority-check by setting the return code in SY-SUBRC
  • substitute a database query by populating the internal table with well known values
  • create test doubles instead of test unfriendly depended on objects
  • validate content instead of writing it to database,

 

Methods of test classes basically replace the code of the test seam with the code of the test injection. The code of the test injection gets executed in the runtime context of the test seam. Consequently the code of the test injection has access to variables and members visible to the domain code only. Controversially the code in the test injection has no access to variables visible to the method with the injection. If you desire to pass content from the test class to the injected code you may consider the use of global variables. Although the test seams are declared within the domain code, they do not alter the behaviour of the domain code for the productive use case. Therefore test seams have not the smell of the anti-pattern "Test code in Production".


Test seams are expected to be especially useful to:

  • get legacy code under test
  • substitute dependency that shall not get exposed

Test seams are not the first choice for:

  • integration and component tests - as test injections are restricted to the same program
  • scenarios where dependency shall get exposed by object seams for architectural reasons

 

Try it and judge how to benefit from this new unique test technique in ABAP.

 

Example Snippet: Replace Authority Check

 

Domain Code with SeamTest Code with Injection



test-seamauthorization_Seam.


     authority-ckeck

       object'S_CTS_ADMI'
       id'CTS_ADMFCT'

       field'TABL'.


end-test-seam.


if( 0 eq sy-subrc ).

  is_Authorized = abap_True.
endif.




test-injectionauthorization_Seam.


  sy-subrc = 0.

           

end-test-injection.

 

Example Snippet: Substitute Database Query With Well Known Content

 

Domain Code with SeamTest Code with Injection


test-seamread_Content_Seam.


  select * fromsflight

    into table @flights[]

    where

      carridin @carrid_Range[] and

      fldateeq @sy-datum.

 

end-test-seam.
 


test-injectionread_Content_Seam.


  flights =

    value #(

      ( carrid = 'LHA'

        connid = 100seatsmax = 30 )

      ( carrid = 'AF3'

        connid = 7seatsmax = 1 ) ).


end-test-injection.

 

Example Snippet: Inject Test Double Instead of Test Unfriendly Dependency

 

Domain Code with SeamTest Code with Injection

test-seaminject_Double_Seam.      


  me->f_Repository =

    new zcl_Db_Query( ).


end-test-seam.
 

test-injectioninject_Double_Seam.     


  me->f_Repository =

   newth_Dummy_Repository( ).  

 

end-test-injection.


Example Snippet: Validate Instead of Writing to Database Table

 

Domain Code with SeamTest Code with Injection


test-seaminject_Validate_Seam.


  modify sflight

   fromtable @altered_Fligths[].     

 

end-test-seam.
 


test-injectioninject_Validate_Seam.


  cl_Abap_Unit_Assert=>assert_Equals(

    act = altered_Flights[]

    exp =

      th_Global_Buffer=>exp_Flights[] ).


end-test-injection.


Full Example: Legacy Function Module With Test Seams

For example the  fury function module RS_AU_SAMPLE_PROPOSE_BOOKING mixes up authorisation, database access and business logic. In such a case one can embrace the authorisation and the repository logic each with a test seam as shown below.

 

function rs_Au_Sample_Propose_Booking   importing     value(i_Carr_Id) type s_Carr_Id     value(i_Conn_Id) type s_Conn_Id     value(i_Flight_Date) type s_Date   exporting     value(e_Booking_Id) type s_Book_Id   exceptions     not_Authorized     invalid_Flight     no_Free_Seats.   data:     is_Authorized      type abap_Bool,     flight             type sflight,     total_Of_Bookings  type i.   test-seam authorization_Check.     authority-check object 'S_CTS_ADMI' id 'CTS_ADMFCT' field 'TABL'.     if ( 0 eq sy-subrc ).       is_Authorized = abap_True.     endif.   end-test-seam.   if ( abap_False eq is_Authorized ).     message 'You not authorized to issue bookings'(noa) type 'E' raising not_Authorized.   endif.   test-seam read_From_Db.     select single *       from sflight into flight       where         carrid = i_Carr_Id         and         connid = i_Conn_Id         and         fldate = i_Flight_Date.     select count( * )       from sbook       into (total_Of_Bookings)       where         carrid = i_Carr_Id       and         connid = i_Conn_Id       and         fldate = i_Flight_Date.   end-test-seam.   " validate content   if ( flight is initial ).     message 'Flight does not exist'(nof) type 'E' raising invalid_Flight.   elseif ( flight-seatsocc >= flight-seatsmax ).     message 'Limit of Bookings exceeded'(nob) type 'E' raising no_Free_Seats.   endif.   " propose new id   e_Booking_Id = total_Of_Bookings + 1.
 endfunction.

The test injection of test class tc_Authorization_Check alters the content of the state variable is_Authorized in with literals. Please note it is not possible to pass the parameter i_Is_Permitted directly as this variable is not known in context of the seam. The code injected into the seam has access to the same artefacts as the domain code only!

class tc_Authorization_Check definition for testing risk level harmless.  private section.    methods:      pass_Permission_Check    for testing,      raise_Missing_Permission for testing,      set_Authorization        importing   i_Is_Permitted    type abap_Bool,      has_Passed_Authorization_Check        returning   value(result)       type abap_Bool.
endclass.
class tc_Authorization_Check implementation.  method pass_Permission_Check.    set_Authorization( abap_True ).    cl_Abap_Unit_Assert=>assert_True( has_Passed_Authorization_Check( ) ).  endmethod.  method raise_Missing_Permission.    set_Authorization( abap_False ).    cl_Abap_Unit_Assert=>assert_False( has_Passed_Authorization_Check( ) ).  endmethod.  method set_Authorization.    " the code within the INJECT SEAM statement will substitute    " the code within the according TEST SEAM statement in the same program    " please not the statements within the body may only make use of variables    " visible in the context of the seam.    if ( abap_True eq i_Is_Permitted ).      test-injection authorization_Check.        is_Authorized = abap_True.      end-test-injection.    else.      test-injection authorization_Check.        is_Authorized = abap_False.      end-test-injection.    endif.  endmethod.  method has_Passed_Authorization_Check.    call function 'RS_AU_SAMPLE_PROPOSE_BOOKING'      exporting     i_Carr_Id =     ''                    i_Conn_Id =     0                    i_Flight_Date = sy-datum      exceptions    not_Authorized = 1                    others =         9.    if ( 1 = sy-subrc ).      result = abap_False.    else.      result = abap_True.    endif.  endmethod.
endclass.

 

The test injection of test class tc_Propose defines in the setup method a static public member (global) variable that shall be used instead of the database query. As the static public member is visible to the domain code, the injected code and the domain code direct assignments are possible.(See also test class include LRS_AU_SAMPLE_TEST_SEAMST99 / SAP_BASIS 7.50 onwards).

 

" The test class 'tc_Propose' makes use of the test seam 'authorization_Check'
" to bypass the authorization check and makes use of the test seam
" 'read_From_DB' to provide well known input to be business logic. Finally
" the output of the business logic gets exercised and checked.
" As local data / private members of the test class can not be used in the
" Injection the test class exposes the test data via public attributes, another
" possibility might have been public getter methods.
class tc_Propose definition for testing risk level harmless.   private section.     class-data:       fg_Flight                type sflight,       fg_Total_Of_Bookings     type i.   methods:     setup,     book_Non_Existing_Flight_Fails for testing,     book_Full_Flight_Fails for testing,     book_Available_Flight for testing.
endclass.
class tc_Propose implementation.  method setup.    test-injection read_From_Db.      flight =              th_Dummy_Repository=>flight.      total_Of_Bookings =   th_Dummy_Repository=>total_Of_Bookings.    end-test-injection.    test-injection authorization_Check.      is_Authorized = abap_True.    end-test-injection.    clear th_Dummy_Repository=>flight.    clear th_Dummy_Repository=>total_Of_Bookings.  endmethod.  method book_Non_Existing_Flight_Fails.    call function 'RS_AU_SAMPLE_PROPOSE_BOOKING'      exporting     i_Carr_Id =     ''                    i_Conn_Id =     0                    i_Flight_Date = sy-datum      exceptions    not_Authorized = 1                    invalid_Flight = 2                    no_Free_Seats =  3                    others =         9.     cl_Abap_Unit_Assert=>assert_Subrc( act = sy-subrc exp = 2 msg = 'no flight' ).  endmethod.  method book_Full_Flight_Fails.    constants:  c_Count_Bookings type i value 10.    th_Dummy_Repository=>flight-seatsmax = c_Count_Bookings.    th_Dummy_Repository=>flight-seatsocc = c_Count_Bookings.    th_Dummy_Repository=>total_Of_Bookings = c_Count_Bookings.    call function 'RS_AU_SAMPLE_PROPOSE_BOOKING'      exporting     i_Carr_Id =     ''                    i_Conn_Id =     0                    i_Flight_Date = sy-datum      exceptions    not_Authorized = 1                    invalid_Flight = 2                    no_Free_Seats =  3                    others =         9.     cl_Abap_Unit_Assert=>assert_Subrc( act = sy-subrc exp = 3 msg = 'no seats' ).  endmethod.  method book_Available_Flight.    constants:  c_Count_Bookings type i value 10.    data:       next_Id type s_Book_Id.    th_Dummy_Repository=>flight-seatsmax = c_Count_Bookings + 10.    th_Dummy_Repository=>flight-seatsocc = c_Count_Bookings.    th_Dummy_Repository=>total_Of_Bookings = c_Count_Bookings.    call function 'RS_AU_SAMPLE_PROPOSE_BOOKING'      exporting     i_Carr_Id =     ''                    i_Conn_Id =     0                    i_Flight_Date = sy-datum      importing     e_Booking_Id = next_Id      exceptions    not_Authorized = 1                    invalid_Flight = 2                    no_Free_Seats =  3                    others =         9.      cl_Abap_Unit_Assert=>assert_Subrc( act = sy-subrc exp = 0 msg = 'return code').      cl_Abap_Unit_Assert=>assert_Equals(  act = next_Id exp = c_Count_Bookings + 1 msg = 'proposed id' ).  endmethod.
endclass.

ABAP Function List in Notepad++

$
0
0

Hi, everyone!

 

How many times either for one reason or another I play us to edit or revise code offline and if the Syntax Highlighting recognition is fantastic (please visit the post of Manish Kumar for add that feature ABAP Syntax Highlighting in Notepad++ Part 2)
https://upload.wikimedia.org/wikipedia/commons/0/0f/Notepad%2B%2B_Logo.png
But sometimes you need to edit quickly in Notepad ++ and you are missing one of the useful features .... The  function List.


Function List Panel is a zone to display all the function (or method) find in current file. User can use Function List Panel to access to a function definition quickly by double clicking function item on the list.

Example_01.jpg

Ok, friends hope you like it and to get down to work.

1-Add the feature Syntax Highlighting for ABAP

please visit the post of Manish Kumar for add that feature ABAP Syntax Highlighting in Notepad++ Part 2


2-File to Modify

To make Notepad++ recognize ABAP function lists, we need to modify the file:

C:\Users\your_user_name\AppData\Roaming\Notepad++\functionList.xml

 

3-XML Nodes

Add to Node <associationMap> the entrie

<associationuserDefinedLangName="ABAP"id="abap_syntax"/>

Example_02.jpg

and then add to node <parsers>

Example_03.jpg

this part of code is in the attachment file

4-Save,Reset the application & enjoy!


Any comments or improvement is welcome

Viewing all 44 articles
Browse latest View live


Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>