Sie sind auf Seite 1von 10

ABAP Development: ABAP News for Release

7.50 - Test Seams and Test Injections


Posted by Horst Keller 23 Oct, 2015
Writing ABAP Unit tests can be somewhat cumbersome if the code to be tested is not suited for automatic
tests. All the hubbub about mock frameworks or test driven development isn't worth a cent if you have to deal
with code that never came in touch with the concept of separation of concerns. Imagine you have code to
maintain, that depends on database contents or calls UI screens and your boss wants you to increase the test
coverage of the department - a real life scenario? Yes, at least in my life. If you cannot redesign and rewrite
the whole application, as a workaround you make the code test dependent. This is regarded as bad style, but it
helps.
As a simplistic example take a method that gets data from a UI screen but should be tested by a module test.
Normally there is no UI available during the test. Setup and teardown methods also do not help as they might
do for selecting data from a database by providing test data. A workaround before ABAP 7.50 was a free-style
test flag, e.g. as follows:
CLASS cls DEFINITION.
PUBLIC SECTION.
METHODS get_input
RETURNING
VALUE(input) TYPE string.
PRIVATE SECTION.
DATA test_flag TYPE abap_bool.
ENDCLASS.
CLASS cls IMPLEMENTATION.
METHOD get_input.
IF test_flag IS INITIAL.
cl_demo_input=>request( CHANGING field = input ).
ELSE.
input = 'xxx'.
ENDIF.
ENDMETHOD.
ENDCLASS.

Generated by Jive on 2016-05-29+02:00


1

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

The test method of a test class that is a friend of the class to be tested can influence the method by setting the
test flag.
CLASS tst DEFINITION FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT
FINAL.
PRIVATE SECTION.
METHODS test_input FOR TESTING.
ENDCLASS.
CLASS tst IMPLEMENTATION.
METHOD test_input.
DATA(oref) = NEW cls( ).
oref->test_flag = abap_true.
DATA(input) = oref->get_input( ).
cl_abap_unit_assert=>assert_equals(
EXPORTING
exp = 'xxx'
act = input ).
ENDMETHOD.
ENDCLASS.

Bad style and not governed by any conventions. To overcome this, with ABAP 7.50 the concept of test seams
and test injections is introduced:
CLASS cls DEFINITION.
PUBLIC SECTION.
METHODS get_input
RETURNING
VALUE(input) TYPE string.
ENDCLASS.
CLASS cls IMPLEMENTATION.
METHOD get_input.

Generated by Jive on 2016-05-29+02:00


2

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

TEST-SEAM fake_input.
cl_demo_input=>request( CHANGING field = input ).
END-TEST-SEAM.
ENDMETHOD.
ENDCLASS.

With TEST-SEAM - END-TEST-SEAM a part of the code is defined as a test seam that can be replaced by
test friendly code during testing. No selfdefined attribute is necessary and the test class does not have to be
a friend of the class to be tested any more (as long as public methods are tested only). You don't need an
alternative implementation inside the production code because this is transferred to the test code The test
method might look as follows now:
CLASS tst DEFINITION FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT
FINAL.
PRIVATE SECTION.
METHODS test_input FOR TESTING.
ENDCLASS.
CLASS tst IMPLEMENTATION.
METHOD test_input.
TEST-INJECTION fake_input.
input = 'xxx'.
END-TEST-INJECTION.
DATA(input) = NEW cls( )->get_input( ).
cl_abap_unit_assert=>assert_equals(
EXPORTING
exp = 'xxx'
act = input ).
ENDMETHOD.
ENDCLASS.

With TEST-INJECTION - END-TEST-INJECTIONM a test injection is defined that replaces the test seam of
the same name during test execution. A test injection can be empty and then simply removes the respective
test seam during testing. Test injections can be defined in test includes of global classes and function groups.

Generated by Jive on 2016-05-29+02:00


3

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

For more information, more use cases, and more examples see Test Seams.
2885 Views Tags: abap

Andrew Barnard in response to Paul Hardy on page 4


29 May, 2016 9:27 AM
I can't help but think that Test Seams have been introduced to help SAP itself implement (some kind of) testing
around those enormously large function groups that underpin the old but widely used transactions in ECC. I'm
thinking about quality / maintenance notification, maintenance order, production order / maintenance order /
network confirmations etc - the ones you wouldn't touch until you had some means of testing in place.
Gabor Farkas in response to Paul Hardy on page 4
13 Apr, 2016 2:17 PM
Global all-static classes are easier to convert into testable code than old spaghetti programs so I wouldn't use
it there. If you have a global class with static methods, you could just delegate the calls to an instance which
can then be made testable (probably not by breaking the dependencies into classes right away, but with the
"subclass and override" pattern).
Paul Hardy
13 Apr, 2016 1:23 PM
I quite agree this has no place in any new programs. The debate seems to be - does this technique have any
place anywhere?
From my understanding the Test Seam concept is intended to be a quick and dirty workaround to add unit
tests to "legacy" code (Michael Feathers defines legacy code as code with no unit tests, so if you wrote an OO
program in ABAP 7.50 yesterday with no tests you have written legacy code).
In my experience the sort of code where database reads and UI logic and all the other dependencies are
all mixed together like a scrambled egg tend to be executable programs and DYNPRO module pools. You
cannot use test seams in either of those, so if you want to bring that code under test then doing things properly
(breaking the dependencies into classes) is the only way forward, probably a good thing too.
If a global class has the same problem - all different dependencies glued together with the business logic then OH DEAR whoever wrote the class did not have much grasp of OO principles, it is probably a function
module or executable program mutated into a class with all the procedures changed to methods with no further
changes, everything probably static, thus totally missing the point. Sadly I have seen quite a few global classes
like that, even in standard SAP.
So, in the areas where you can use test seams e.g. a function module, the question is - which is more effort?
To do things the correct way and split each sort of dependency, the database access (or whatever) into it's own
class so it can be subclassed for unit tests, or to surround each such database access with a test seam and put
in a test injection in the unit tests.
I think the answer is fairly clear for anything non-trivial. I'm with Lucas on this.

Generated by Jive on 2016-05-29+02:00


4

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

Cheersy Cheers
Paul
Gabor Farkas
27 Jan, 2016 1:33 PM
I think this can be useful but it should be emphasized that the primary (or sole) use of the test seams is to
make legacy code testable - using it for new code seems to be bad practice.
Klaus Ziegler in response to Lucas Ttreault on page 7
3 Dec, 2015 12:18 AM
For example TEST SEAMS do a great job to get totally untested legacy code under test initially. After the initial
tests have been established one has the option to apply further reworks / refactorings.
The use of TEST SEAMS as step stone towards clean code, seems to me as working effectively with legacy
code.
See also
Working effectively with ABAP legacy code - ABAP Test Seams are your friend
Klaus Ziegler in response to Jacques Nomssi on page 6
2 Dec, 2015 11:54 PM
Hello Jacques,

ABAP TEST-SEAMS are available only for programs with dedicated test includes, that is class.pools and
function-pools. Within these program types one can inject into any executable location, including methods of
local classes or even forms.
The package SABP_UNIT_SAMPLE contains the class-pool CL_AU_SAMPLE_TEST_SEAMS which
showcases the use of TEST SEAMS in combination with local classes.
Hope this clarifies
Klaus
See also
Working effectively with ABAP legacy code - ABAP Test Seams are your friend
Horst Keller in response to Jacques Nomssi on page 6
10 Nov, 2015 8:07 AM

Test seams are ignored in production use of programs

Generated by Jive on 2016-05-29+02:00


5

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

Hmm, the translation to English changed the original sentence a bit. A better translation might be "Testseams
do not influence the productive usage of programs". Nevertheless also the above sentence is OK, because test
seams are ignored by the compiler in production systems.

the limit to global classes and function pools is a hindrance for those like me who favor local
classes.

Unfortunately, test injections are possible in test includes only. And test includes are possible for class pools
and function groups only. For other program types there are technical restrictions. (pls. don't ask me why ...)
Horst
Jacques Nomssi
9 Nov, 2015 11:06 PM
Hello Horst,
from the documentation:
Test seams are ignored in production use of programs.

I am correct to assume it should read Test injections instead?


We can already inject seams with by method redefinition, but I would gladly use a TEST-SEAM to isolate
OpenSQL statements in unit tests. But... the limit to global classes and function pools is a hindrance for those
like me who favor local classes..
best regards,
JNN
Horst Keller in response to Lucas Ttreault on page 7
7 Nov, 2015 10:35 AM
The only reason to go write tests for legacy applications is if you intend to make changes to
it
A directive to increase test coverage can be another reason. Yes, that normally results in smoke tests that in
most cases do not have any functional sense. But a full test coverage might at least help to detect dead code
that never can be used because its execution leads to exceptions. And, hey, even smoke tests might reveal
one or the other error in old code you havent been aware of.
Wilbert Sison in response to Horst Keller on page 8
6 Nov, 2015 12:27 AM
Thank you for the response Horst. It makes sense.
More power to you and SAP for promoting the Unit Testing practice.

Generated by Jive on 2016-05-29+02:00


6

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

Cheers,
Wilbert
Lucas Ttreault in response to Suhas Saha on page 7
5 Nov, 2015 8:29 PM
The only reason to go write tests for legacy applications is if you intend to make changes to it. Otherwise you're
writing tests for fun and wasting your time.
If you're already making changes to the program then you can figure out a way to build real 'test seams' and
not use these features. Michael Feathers defines test seams as "a place where you can alter behaviour in your
program without editing in that place" in his book Working Effectively with Legacy Code.
I would suggest that anyone who thinks these new features are a good idea go read that book...
Suhas Saha in response to Lucas Ttreault on page 7
5 Nov, 2015 8:14 PM
Writing test code in with your production code is just pollution and I will make sure that my
development team never uses this functionality.

Horst has already made it clear at the very beginning of the blog
If you cannot redesign and rewrite the whole application, as a workaround you make the
code test dependent. This is regarded as bad style, but it helps.
If you need to maintain legacy code without proper SoC, i think this construct is really helpful. If you are
building a new application that's a separate story altogether!
Lucas Ttreault
5 Nov, 2015 7:42 PM
This is crazy! And not at all in a good way.
Writing test code in with your production code is just pollution and I will make sure that my development team
never uses this functionality.
If you can't figure out how to achieve the same with mocks, stubs, test doubles, etc then you have some
seriously bad code that needs refactoring.
Building in ways for people to avoid writing good testable code is not the way to improve the ABAP language.
Tests shouldn't care about the details of HOW something is implemented... Let alone be PART of that
implementation!
Horst Keller in response to Suhas Saha on page 8
5 Nov, 2015 6:53 PM
I thought you're the ABAP boss

Generated by Jive on 2016-05-29+02:00


7

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

Just hope that the real ABAP Boss(es) don't see that ...
Suhas Saha
5 Nov, 2015 4:09 PM
your boss wants you to increase the test coverage of the department - a real life scenario?
Yes, at least in my life.

I thought you're the ABAP boss (at least for me). #justkidding

Anyway i have to admit that with each release ABAP is getting cooler
Horst Keller in response to Wilbert Sison on page 8
5 Nov, 2015 4:01 PM
Hi Wilbert,
I discussed the idea of implicit test seam points, where only the positions after METHOD/FUNCTION and
before ENDMETHOD/ENDFUNCTION make sense, but the result is, that it is not worth the effort. Since Seams
and Injections are located in the same compilation unit anyway, it is not too big an effort to declare the seams
explicitely.
Regards
Horst
Wilbert Sison in response to Horst Keller on page 9
5 Nov, 2015 5:28 AM
Hi Horst,

The "dynamic test-seam" was just wishful thinking.


In order to instrumentalize code substitution, I realize that it may require fundamental changes to the runtime
environment. The runtime would need to make a substitution at the point of execution. At every call, it would
need to look at the definitions that has been declared in the unit test to see if the invocation can be replaced.
The "implicit team seam points" seem to satisfy what I'm thinking of. If we already have 'explicit test seam's having the runtime recognize implicit ones around functions/methods sounds like it's not far of a jump.
While it sounds like it promotes 'bad practice' in design. It may just be the thing to make the 'good practice' of
unit testing wide-spread.
By the way, any chance of a down-port to 740?
Cheers!
Wilbert

Generated by Jive on 2016-05-29+02:00


8

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

Horst Keller in response to Rdiger Plantiko on page 9


29 Oct, 2015 8:48 AM
A keyword "TEST-SEAM" in productive code feels like a pollution, almost like having a test
mode flag in production code
Yes, but only almost. The benfit is that you get rid of the alternative implementation inside the production code.
At least that is transferred to the test code.
Nice post, b.t.w.
Rdiger Plantiko
29 Oct, 2015 8:43 AM
Nice concept - similar in spirit to extension-points.
The only point that I don't like is the naming of the new keywords. A keyword "TEST-SEAM" in productive code
feels like a pollution, almost like having a test mode flag in production code.
On the other side, these test seams are only necessary for code which is dirty anyway, since it doesn't properly
separate the UI or database layer from its logic layer. So it doesn't matter in the end.
Horst Keller in response to Wilbert Sison on page 9
29 Oct, 2015 8:18 AM
unit test execution can dynamically make the substitution - without the application having
defined a TEST-SEAM first.

Hi Wilbert,
I wonder how the unit framework should know which code to replace with what if you do not instrumentalize the
application explicitly.
Are you thinking in the direction of implicit test seam points, similar to the infamous implicit enhancement
points? Or do you think about something like "replace lines from n1 to n2 in procedure x" (application code
must be stable, then)? Or did I miss something obvious?
Best
Horst
Wilbert Sison
29 Oct, 2015 5:01 AM
Hi Horst,

Generated by Jive on 2016-05-29+02:00


9

ABAP Development: ABAP News for Release 7.50 - Test Seams and Test Injections

Nice! Locally, we argued a lot about the "mock frameworks". We tried local adapter classes/our custom
Z*Mock/ MockA/ Test Double Framework. Nothing seems to have really bedded down and it's a real pain
getting people to agree on it.
One of the issues was the amount of code that has to be put in place to encapsulate non-testable code. This
is both a time issue (ie to the point where it has to be approved for build) or as you've put it - an issue with
conventions (ie diff developers with different ideas on how to create the testable layer).
This may just help reduce that issue and get people over the line.
Just for consideration : I'd like to be able declare a TEST-INJECTION for a method/function and the unit test
execution can dynamically make the substitution - without the application having defined a TEST-SEAM first.
Is this a possibility? I'm not sure if that dynamic approach will lead to worse code in general. As you've alluded
in your blog - separation of concerns (data/logic/ui) is something that we should aspire to. But we do seem
to have a lot of non-testable OO/Non-OO codebase. Taking it one step further and having the dynamic SEAM
may just lead to more adoption of unit testing.
Kind Regards,
Wilbert
Horst Keller in response to Victor Ionescu on page 10
26 Oct, 2015 11:30 AM
syntax check, yes (of course)
code completion, up to now no, neither in SE80 nor in ADT
Victor Ionescu
26 Oct, 2015 11:20 AM
Nice! I wonder if during implementation of the unit test you actually have access to the context of the source
code being tested.
e.g. does syntax check & auto-complete work within a TEST-INJECTION?

Generated by Jive on 2016-05-29+02:00


10

Das könnte Ihnen auch gefallen