You are on page 1of 23

openSAP

Writing Testable Code for ABAP


Week 6 Unit 1

00:00:09 Hello. Welcome back.


00:00:10 We're in Week 6 now. In Unit 1, we're going to focus on providing testability for existing code.

00:00:17 And this week really, we want to focus... It's like the culmination of the whole course, if you will.

00:00:22 At least, how to do all this agile development, unit testing in existing code when it's typically not
written
00:00:32 to be testable to begin with. And so we will focus on things that help you there,
00:00:37 and recap the tips and tricks that we explained on the way. So providing testability for existing
code.
00:00:47 When you have code that's already running, and you want to provide testability,
00:00:51 you have a dilemma. And in order to write tests, you need
00:00:55 to make changes to the product code to make it testable. Things like, depending on what you
do, maybe
00:01:02 provide injection methods, move code around, depending on what you want to do.
00:01:07 And that's, of course, dangerous because you could break things. And normally you would
say, I would make changes
00:01:13 only if I have tests so that I can make sure that the changes I make don't break the code.
00:01:19 So you need tests to make the change, but you need to make changes to provide stability.
00:01:24 So you're kind of stuck. But the solution is actually relatively simple.
00:01:31 You have to say, I'm considering two steps in refactoring. One is provide testability.
00:01:35 You will do only very small, safe refactorings. And the most safe and simplest ones
00:01:40 are things like constructor injection with an optional parameter, or something like that.
00:01:46 Or a dependency lookup that we showed in the last week. And we showed you how to use
this, even
00:01:51 in a larger setting, when you have a big component and you want to eliminate one dependency
after another.
00:01:58 So this is clearly a safe refactoring. And you can actually do it one by one.
00:02:03 And then, as soon as you're able to, write the tests that you want to write.
00:02:07 And then do the next step, and write a test for that case so that you don't go like, oh, I'm
making a hundred changes
00:02:12 and I'll start writing tests. That's not the way we want to do this.
00:02:16 But there are also some tools that are special. They're actually available in ABAP
00:02:21 to help you in different places. And we'll look at some of those later.
00:02:26 So what are safe refactorings for testability? Hiding legacy code behind interfaces
00:02:33 to test only your code and actually be able to switch it easily and safely with test doubles.
00:02:39 But also, sometimes you have to start earlier, where you think, I have a report, what in the
world do I do there?
00:02:45 And I have a function module and what do I do there? So then you have to maybe move that
code first
00:02:50 into an object-oriented style syntax to be able to go and move on from there.
00:02:56 And that's what you're going to show now. Yeah.
00:03:01 So we won't go into the code. We'll just show it schematically here.
00:03:07 Consider here, on the left side we have report. The report has sections.
00:03:13 So in the first section directly after the report statement, we have global variables.
00:03:21 Then we have select the option variables. Then we have the select options, which define the
UI
00:03:27 at the beginning of the report. And there are several sections.
00:03:31 We only picked two of them. So start of selection and end of selection, for example,
00:03:36 are two of them. And they contain some ABAP code.
00:03:41 Just sequential ABAP code, with ifs and everything, but it's still ABAP code. And so how could
you transfer something like that
00:03:53 into the object-oriented world? And you can do that mechanically.
00:03:59 You just think of, OK, let's put a class next to it. And then the global variables, move them as
global variables into that class.
00:04:08 Static variables then. Static variables, yeah.
00:04:12 And-- oh, not really static. Not necessarily.
00:04:15 No, no, no. Member variables.
00:04:17 I would start with member variables. Yeah.
00:04:18 Let's start with that. Yeah.
00:04:19 And then each of the sections, just move them into a method. Just call it like the section, for
example.
00:04:27 As made here, METHOD Start_of_selection. And then move the ABAP code over there.
00:04:34 And then end of selection, same thing. Just move it into a method, which is there.
00:04:42 And so that's the first step. Now you have some syntax errors.
00:04:46 Because on the left side, everything was global. And on the right side, that's no longer the
case.
00:04:52 So if some data statement was done in start of selection, it was visible in end of selection.
00:05:01 With methods, that's no longer the case. So there you have to fix that.
00:05:10 And that's very individual. So there's no picture we can draw
00:05:14 and say, yeah, it's like this, and this, and this. But in the end, what you want in your report
00:05:20 is the select option variables and the select option statements. They are still in the report.
00:05:27 They stay there. And then in the start of selection,
00:05:32 you create that new class you have. And then you pass all the select options,
00:05:41 as they were set by the user before he executed the report. You give that to the constructor of
that class.
00:05:53 OK, that's one call. Create object and pass these variables in.
00:05:58 You could also have a setter and set them somehow. So that's totally up to you.
00:06:05 And then you start that method, which contains the code which was formerly in start of
selection.
00:06:13 And then you add another call in your other sections where you call the corresponding
methods, which are now in the class.
00:06:24 And as I said, there will be some syntax errors because of variables which are no longer
visible.
00:06:32 There you have to find a solution. Either get rid of them if they are no longer necessary...
00:06:38 If it was an illegal reuse of the same variable but with a different semantic, then OK, you found
it, great.
00:06:44 Now you can fix it and name it differently, name it more semantically.
00:06:49 Or if it's really something which has to be more global but was defined in one of the sections,
00:06:54 then move it up as a member variable in the class. So just think about these.
00:07:00 And as a tip, the select option variables are also global variables in the report.
00:07:10 And you pass them into the constructor or into the setter. And it's a good practice to then store
them
00:07:18 on some member variables, which are named a little bit semantically better named then these
short select option variables
00:07:32 because there was a limitation on that. You no longer have that short limitation
00:07:37 when you are in the class environment. So the global variables are really member variables.
00:07:44 You may have to move something from the method level to that level as needed, if you see
that.
00:07:50 But otherwise, you try, of course, to keep things as local as possible.
00:07:53 Try to keep everything as local as possible.
00:07:58 And also, this is only the first step. We are not saying now you're done.
00:08:03 No, you're not. Because if you then look at this class,
00:08:08 you have methods which are not really named that semantically. And also, your report and the
code in there...
00:08:17 it does not need to be one class. It can be many classes.
00:08:22 Maybe it should be many classes because different things are working there together.
00:08:26 But this is a starting point. Now you're in the object-oriented world.
00:08:30 And now you can start refactoring. You can start writing tests for it.
00:08:33 Now you can apply everything you heard in this training. Right.
00:08:37 And actually, we don't cover this very much in our course because that was not the focus of
our course,
00:08:43 but at this point, I highly recommend this book by Michael Feathers, Working Effectively with
Legacy Code,
00:08:52 because there is a lot of refactorings. Once you're at the starting point,
00:08:55 then you still have probably start of selection and maybe a thousand lines of code.
00:08:59 And that's, of course, a mess. How can you clean this up?
00:09:02 And there are patterns that are well established and they're well described in this book.
00:09:05 Things like extract method. You have three lines that don't belong,
00:09:10 or you want to get rid of these three lines in a test. Well, you can extract them in a method.
00:09:16 And then you can subclass a test double if you want to do it that way, and just override it.
00:09:20 Or if you have something bigger, you can do it with interfaces. So there's all kinds of tricks to
do refactorings which
00:09:27 are not focused on testability. This one would be.
00:09:30 But also just making the code better in general. And this book is an excellent choice for that.
00:09:36 And also, there are some videos on the SAP Agile Software Engineering channel. There's a
YouTube channel with some videos
00:09:47 that have to do with how to test big chunks of code in one piece. So this has to do more with
testing with large parameter
00:09:55 sets, huge possible combinations, and so forth. But you will also typically run into this
00:10:00 if you want to test this because it's already a big block of code.
00:10:03 And how to deal with that is also described there.
00:10:08 So that's it for this unit. See you in the next unit.
00:10:13 Bye-bye.
Week 6 Unit 2

00:00:08 Welcome to Week 6, Unit 2, Test Double Frameworks Yeah, we're going to call...
00:00:16 talk about test double frameworks, which means tools that make writing tests easier
00:00:22 for certain different environments. And actually, there's quite a bit that ABAP also offers here.

00:00:28 And we have four different ones that we'll go through now, one by one. So the first one is the
so-called ABAP test
00:00:34 double framework. And logically, what it does is basically
00:00:38 if you have an interface, a global interface, it allows you to generate classes on the fly,
00:00:44 and you don't have to write it down. But you basically say, when this method is called,
00:00:49 then do this and this. And it's part of your test setup.
00:00:53 So you don't actually have a class test double written. It's just in the part of the setup,
00:00:59 you're defining what it is supposed to do when a certain method is called.
00:01:03 And sometimes you'll only need one method, and then that's really a time saver.
00:01:07 So what does this look like? Let's look on the right-hand side there on the code.
00:01:13 There is a cl_abap_testdouble. That's the base class that gives you this functionality.
00:01:18 So when you start there, you have a create method, and then you specify the interface
00:01:23 for which this test double class is supposed to be generated. And actually, there's something
generated underneath.
00:01:30 But basically, then it kind of has this interface. And then because, in the end, you want to be
able
00:01:36 how can you talk to this class. So this test double implements that interface.
00:01:41 So that's step number one. And then you have to specify what happens for each method
00:01:47 possibly that you want to call. And this second step actually happens in two steps,
00:01:51 in step 2 and 3, and which is maybe a little bit unintuitive. But actually, it makes sense if you
think about it.
00:01:59 So first, in step 2, you have this call, where it's a static call, where you're
00:02:06 saying when the next method is called, how should it behave? And here you see the configure
call.
00:02:15 You pass in the test double handle that you got in before. And then you say, it should...
00:02:21 And it follows this builder pattern where you have all these arrows one
00:02:25 by one where you can specify one attribute after another to the same entity. This is a nice little
pattern.
00:02:34 So what you're saying is, returning, you want to return true.
00:02:38 You could specify which parameters are to be called for this, or tested, and so forth.
00:02:44 But here it says ignoring all parameters. And then there is an end expect, how many times, for
instance.
00:02:51 In this case, you can be called. It's called once.
00:02:54 You can actually also specify the number and so forth. And this is actually, if you think about it

00:03:01 in terms of test doubles, this is a hardcore mock because you are very specific.
00:03:05 You say these are the parameters, so many times I want to be called, and then returning
00:03:09 this and this, and so forth. So it's very specific.
00:03:12 So you first specify what's supposed to be with the call, but then what is the call?
00:03:18 So this is not specified yet. And that's number 3.
00:03:21 And so in step number 3, again, you start with a test double. And it looks like you're calling the
method.
00:03:29 But you're not really calling it because you're talking to the double.
00:03:31 And this call, with specifying the parameters, finishes or completes the definition
00:03:38 that you started earlier in step 2 and says, OK, the method that I talked about in step 2
00:03:42 is actually step 3. And this is then the behavior that's
00:03:47 supposed to be called before method two_double. And of course, it would be in real life, a
different name.
00:03:53 Yes, absolutely. But method two_double, where is it defined?
00:03:56 Well, in the interface, some global interface. And in this case, you may wonder, well,
00:04:04 it says ignoring all parameters. Why do I have to specify them?
00:04:07 Well it's because... Syntax.
00:04:08 Yeah, it's not an optional parameter. So you have to specify even if the mock says
00:04:13 I don't want to evaluate them. But you have the same story in the stub.
00:04:18 You have to get 10 parameters, and then you don't even look at them.
00:04:21 So and what happens under the hood is that a class is generated that behaves...
00:04:27 a local class that is hidden, kind of, and it behaves... it implements this.
00:04:32 And then after the test, it's gone. It's gone, yeah.
00:04:35 So if you need to configure more than one method, then you just repeat step 2 and 3 for each
method
00:04:42 you want to configure. Exactly.
00:04:44 And this framework replaces the implementation we did so far in the training for our test
doubles.
00:04:54 So you can replace that with the framework. But you can also say it the other way around.
00:04:58 Everything which is done here, you can do also with handmade test doubles.
00:05:04 So and we will show you more test double frameworks. That's not the case with all of them.
00:05:10 But here-- everything which is done here-- can also be done manually.
00:05:15 And maybe one thing to say is that it only works for global interfaces.
00:05:18 Yes, that's a limitation of the area. So you cannot replace classes or use a test double as a
subclass
00:05:24 and so forth. So it's kind of a matter of taste.
00:05:27 Do want to do it-- is this shorter?
00:05:29 Or do you like to just have a small, local test double definition?
00:05:33 It's a matter of taste. OK, let's come to the next one.
00:05:37 It's called Open SQL test double framework. And that is a really cool one.
00:05:43 And that is one where you have to do quite a lot in order to do what this does for you.
00:05:49 And in the end, you have SQL statements, Open SQL statements, in the middle of ABAP
code.
00:05:59 So ABAP allows you to write your SQL statements in there. And if without that framework, you

00:06:08 have to do something when you don't want that your code actually accesses the database.
00:06:13 Because you mentioned it earlier, the ultimate global variable.
00:06:20 And then you would need some hiding techniques, like put it in an extra method or put it in an
extra class,
00:06:28 and have an interface, and then you take the test double. And then you don't test the select
statement,
00:06:35 or in that statement, or whatever it is, so a lot of effort.
00:06:39 But with this framework, help is there because now you have the possibility
00:06:46 to leave the SQL code where it is and still have the call redirected at some point in the kernel
to a test
00:07:00 double you inject beforehand. And let's look at the code.
00:07:04 The code says it all here. So you have only a very limited set of glue code you need.
00:07:12 So first of all, you start that environment. That's this cl_osql_test_environment.
00:07:19 So you create an environment. And you tell with this call, the framework,
00:07:27 what are the entities which are replaced, so which are no longer the real ones on the
database.
00:07:32 And they are tables. They are tables.
00:07:34 They are views, several things. Things like that.
00:07:38 And in our case, it's called table_1. Let's assume that's a real table name.
00:07:45 So we want to test double this table_1. And you know class_setup has a twin.
00:07:54 That's a class_teardown. And in the class_teardown, you just
00:07:57 destroy this environment again. And then you have in the setup, so before each...
00:08:09 before each call of a new test method, you just clear this double. So everything which was
done in the last test
00:08:20 is then just removed, and the initial state is again there. And then in your test method, it looks
really nice.
00:08:27 You just fill your internal table which is of the same type as the table or the view
00:08:36 you want to cover there. And then you insert that into the environment
00:08:41 with this insert test data. You just plug it in there.
00:08:45 And from that point on, every select which goes towards the database and touches this
table_1 table,
00:08:55 is redirected and goes directly to our internal table. And then you can do inserts there,
00:09:02 do deletes there, do selects on that. So everything is possible, so the whole syntax.
00:09:08 And so that's really nice. So and here we see the story.
00:09:12 We prepared that. So now we inserted our test double.
00:09:15 And then we call our code under test, which is here called method_with_db_statement.
00:09:23 And then the db statements are executed. And in the end, you can,
00:09:28 as done here, still check the direct output. And if you want to check if the content on the
database
00:09:35 is as expected, like the indirect output-- if you want-- so did that method do the right thing
00:09:43 on the database? Then you can, in your then part of the story,
00:09:48 just select the database. And it still goes to the test double.
00:09:54 And check if the content on the database is as you would expect it with your test data.
00:10:01 So really nice, your SQL statements can stay where they are.
00:10:07 And for a test side, you now have really good possibilities to test that.
00:10:12 And you test the SQL statement that you wrote with it. So this is the beauty.
00:10:16 If you have some obstruction on top, your SQL could be wrong and then you wouldn't notice.
00:10:20 That was a blind spot before. If you put it away and replaced it with a test double,
00:10:24 that blind spot is gone. The SQL is now also tested.
00:10:28 And one more thing, you see here at the call, maybe it's just that call and one method.
00:10:32 But actually, think about integration test. If you have one call that has 100
00:10:37 tables underneath-- hopefully you don't want to mock 100 tables.
00:10:40 But something where you maybe only for instance-- a very typical case-- oh, I have
configuration
00:10:44 that I have stored here. And I want to select different cases, right?
00:10:48 So you can have two or three tables that you want to change, but the rest is supposed to run
as before.
00:10:55 Then in you're setup, like test doubles, you don't double classes.
00:10:58 You double tables. And then you can set it up, and then you
00:11:02 can run the whole thing. So there can be a whole big chunk of code
00:11:05 underneath this way, very nice. I mean, there's still one thing to consider.
00:11:10 You make your test depending on these tables. If you check for the specific content on these
tables,
00:11:17 then your test is connected to that. If that behavior changes, your tests will break.
00:11:21 Maybe that's intended, then it's good. Then you see if it breaks.
00:11:25 But if it's not intended, then this is a dependency. So you should always take also care about
that.
00:11:30 But if you already have the dependencies because, for instance, you have legacy code,
00:11:34 this is a very great way to test it that way. Yeah, and then we come to a very similar framework
which
00:11:43 does a similar job when having core data services, so-called CDS views.
00:11:52 And this framework is able to test these. And if you go right to the code here, it's very similar.
00:12:02 Instead of CLOSQL, we have here a CDS test environment. And then also a create call.
00:12:09 And then you'll say, OK, which is the CDS view I want to test? You name it there.
00:12:16 And in the class_teardown, you have the destroy method again. In the setup, you have to clear
doubles again,
00:12:21 all completely similar. And then here you don't test code
00:12:28 in the sense of ABAP code. Here you really test only the CDS.
00:12:34 So that's a core data service. So in your test coding here, you have
00:12:40 to select from this core data service and test that one. So this is the nature of this test
framework.
00:12:48 And this test framework allows you to either do unit tests on core data services,
00:12:56 meaning it cuts all connections directly around the core data service or only the core data
service is executing.
00:13:05 Everything else is a test double. Or a core data service typically is kind of a tree.
00:13:13 It goes like a tree of classes. It's here a tree of core data services.
00:13:20 And with this framework, it's also allowed to cut every branch of that tree on different levels.
00:13:28 And replace it with test data. And replace it with test data.
00:13:30 So at some point in time, the whole tree is cut at some branch level and replaced
00:13:38 with your test doubles. And so you have--
00:13:42 you can even do more than unit tests. And you can test more than only this one core data
service.
00:13:48 You can go all the way down to the real tables, if you like, or stop in the middle.
00:13:56 If you say, OK, this core data service comes from another department.
00:13:59 It's not our job to test that. We cut it here and know what this core data
00:14:04 service shall return. And so a really mighty a tool.
00:14:08 And if you are in the business of writing and testing core data services, here is the tool for you.

00:14:15 And maybe one word is an interesting queue there with the big graph-- or the tree, rather--
00:14:22 of views. So this is especially important in the HANA environment
00:14:25 where the database has very powerful views that do a lot more than just selects, but there
00:14:29 is computation in there. Sometimes really complex things.
00:14:31 So the tree that you're looking at really is a data flow tree-- if you will--
00:14:36 where all kinds of stuff is happening on the way. And sometimes you want to do logical tests
where you say,
00:14:41 I have logically five cases in this thing here, but there is all the stuff underneath.
00:14:45 And sometimes maybe the test data that exists is, oh, we have 1 million lines here, 1 million
lines there.
00:14:52 How can you really test that and be sure that the case that you care about
00:14:55 is in there, and so forth. So you have the same story.
00:14:58 You have dependencies below. There is something that you care about.
00:15:01 The cut is a view that you care about or a section of this tree. And then you want to supply
from the bottom
00:15:08 that data that exactly fits the test case with minimal effort. So it's not just about time, but also
you have to design it.
00:15:15 You have to really think about, what do I put in there? What covers the logical cases?
00:15:20 And so this is very nice that you can manipulate basically this tree at the places
00:15:24 where you care about. And every test can be different.
00:15:28 And also from the tooling, so this tree, there is a graphical representation of the tree.
00:15:35 So the tool really helps you to find these branches and say here, here, and here, I want to cut.

00:15:40 Yeah, really nice. OK, and I think then we-- yeah, then we come to the last one,
00:15:47 ABAP test seams. That's something also available starting with 7.40, I believe,
00:15:52 another way to basically cut out and replace certain lines of code anywhere in the code you
want.
00:15:59 So the basic idea is, let's say, if you look at the product code on the left-hand side here,
00:16:04 let's see, you have some code. And suddenly there's an authority check.
00:16:07 And so you need certain permissions to run it. And what do you do in test?
00:16:10 Do I have to be a certain user? Then I have to assign myself some roles.
00:16:13 And it's actually very complicated. This makes the test very dependent on a huge, big chunk of
context.
00:16:19 And you don't want that. So what you can do is, say, you define a so-called seam.
00:16:27 A seam, remember, a seam is where you cut. So you say, I want to actually, this part here,
00:16:32 from here to here, I want to cut out and then replace-inject other code.
00:16:37 And so here you see a TEST-SEAM on the left-hand side that's actually empty.
00:16:44 So that's weird, you think. Will TEST-SEAM manipulate authority?
00:16:47 You see the same name on the left-hand side. This is defined-- that's something
00:16:51 you define in the test, include in the test code. You say TEST-INJECTION
00:16:55 That's the other side of TEST-SEAM But you use the same name.
00:16:58 And what happens then is when this test runs, when this test code runs through there,
basically
00:17:03 that piece of code is injected into the seam in the product code at that point. So what does this
empty seam do?
00:17:11 Well, it gives you a return code, SUBRC of 0. So even if the authority check failed,
00:17:18 you still get a return code of 0, and then you can continue. So it looks like you had the
permission.
00:17:24 So just with adding those two lines in the product code-- again, we're talking about safe
refactorings--
00:17:30 you can basically circumvent certain troubles that you would have otherwise for testability.
00:17:36 And below, you see another example for a seam where actually there was something inside.
00:17:40 There is a function that you don't want to be in the test. So instead of encapsulating and doing
all this stuff,
00:17:46 you can put a seam around it. And in a test, you can either replace it with something
00:17:51 or you do nothing. And then basically, you remove it.
00:17:54 So that sounds really great. There is just one little problem.
00:17:58 And that it only works, the test code, of course-- as you know-- the test include is part of the
global class--
00:18:04 or of the program, if you will-- it belongs together exactly. And it can only see that global class.

00:18:10 And so it means that the test seams only work within the same program unit, which means the
test code that
00:18:17 belongs to the program, test global that belongs to the class.
00:18:20 So if you think about an integrated test scenario where you have a big hierarchy of classes,
00:18:25 and you want to say that thing down there I want to replace, then you--
00:18:28 It doesn't work. It doesn't work.
00:18:30 You cannot control that. So tests seams are good if you have--
00:18:35 like, the test that you care about, for instance, the report case that we looked at before.
00:18:39 The test for the report will be right there. And so if all the test code is there
00:18:43 and you don't want to control it from the outside, this is a good way to quickly cut certain
pieces
00:18:49 and make it testable. But one word of caution.
00:18:55 This test seam is very powerful. But it can also get very messy if you have a lot of them.
00:19:03 Because we are talking here about code is injected from the right side here to the left side.
00:19:10 And if you have a lot of these code locations, then it's really easy to lose the overview of
00:19:19 what is now injected where? And so for object-oriented environments,
00:19:25 we basically don't recommend to use that. This is more for the conventional ABAP
environment
00:19:35 where you have no other possibility because you are not allowed or don't have the time to do
big refactorings to get
00:19:45 your code-- at least a little bit-- more testable.
00:19:48 And then this might help you to get your job done, to get it tested.
00:19:57 And the nice thing is these TEST-SEAM and END-TEST-SEAM, they have no effect on the
product code.
00:20:05 So you can put it anywhere in the code - it has no effect. It's there, yes.
00:20:11 You can see it in the code. But it only has an effect when you are running tests and then
00:20:19 also only if there is a corresponding test injection with the same name.
00:20:24 So that part is totally safe. You can't do anything wrong there that's in one part.
00:20:28 Yeah, that's true. Yeah, you're right, that's really a consideration.
00:20:31 If you think about well-structured programs, there are method names.
00:20:34 There is maybe classes separated. So you see what logically belongs together
00:20:38 is in one piece. But if you have a couple of functions,
00:20:42 let's say, with 1,000 lines each, and then a test with 20 or 30 fragments and you don't
00:20:48 know which piece goes where, then it's easy to get lost. But you will feel it, I suppose, when it
gets too complicated.
00:20:55 This is something to keep in mind. But in the legacy environment, it can be a good way to start,

00:21:00 and then maybe move into classes later.


00:21:03 So definitely, it's a tool. When you have no other way, this might work.
00:21:09 Use it. It's there.
00:21:12 And I guess that was it for this unit. Then we see you in the next unit.
Week 6 Unit 3

00:00:08 Hello and welcome to Week 6, Unit 3, where we want to talk about continuous integration.
00:00:14 Now so far, we really mostly talked about tests, mostly actually about unit tests and then, in
Week 5 actually, also
00:00:22 about integration tests that verify that the stuff you built on a low level, that
00:00:26 is tested on the unit level, actually works also when you put it together.
00:00:31 And there we talked also about how can you selectively turn on and turn off dependencies so
that you get the test sometimes
00:00:38 fully integrated. Sometimes you want to replace a certain part.
00:00:42 Now, I want to promote a practice called continuous integration, which is about doing certain
integration
00:00:50 tests all the time and running the tests all the time. So the point is to keep the main line
running.
00:00:58 The main line means the code, the system basically, all the code that is functioning in order
00:01:04 to detect errors early. So often when you develop unit test-driven especially,
00:01:10 you will make sure, OK, in my code here, there is no mistakes. This is working because I
00:01:15 have tests that prove it. And then you make a change, you activate it,
00:01:18 and then it is there. But there may be another test or another case
00:01:22 that is using your code where something changed. And so maybe something will break
accidentally.
00:01:28 That's one thing. That's called a regression test.
00:01:31 But the other thing is, of course, that when you think about a big system--
00:01:35 and everybody's writing unit tests, just, of course, not enough, and that's why in the last week
00:01:40 we talked about also the integration tests, that on a higher level you want to see the whole
thing
00:01:45 work together. Remember the test pyramid.
00:01:48 On the bottom, you want to have really intense full coverage. But on going up, you want to
focus
00:01:52 on does this stuff work together, when I set the flag here, does it really get there,
00:01:57 does the data flow work, and so forth. So you need to have tests that make
00:02:02 sure that stuff works together. And so continuous integration really has two aspects.
00:02:09 One is to make sure that these tests are really there in the first place.
00:02:14 And the second thing is, of course, to actually run them all the time, and we'll come to that.
00:02:19 So first on the first aspect, to make sure that the tests are there, some people
00:02:24 think that, well, in ABAP if you activate something it's integrated.
00:02:28 Well, yeah it's compiled, but that's it. If there is no test exercising the code, it's nothing.
00:02:34 So if you can compile it, OK. You'll get an error otherwise immediately.
00:02:37 But throughout that's not really very much. You want to make sure it functions correctly also
00:02:41 in its different usage contexts. And so to make sure, if you have a bigger backlog
00:02:48 item, something that takes work here and several units to be developed or extended
00:02:52 on a lower level to make the higher-level story work, once you did all the pieces that are
covered by unit tests,
00:02:59 you also have to have a so-called acceptance test that makes sure that the whole flow works.
00:03:05 And it also should be automated, of course, because you don't want to keep testing it.
00:03:10 So basically you develop the test bottom up. But when you're done, you want to make sure the
acceptance
00:03:16 tests also work. In fact, some people promote that.
00:03:19 And it's possible just the same way as test-driven development is.
00:03:22 It's called acceptance test-driven development. Also on the higher level, you know the case
00:03:28 that you want to work, and you write a test there. And it will be read all the time until all the
pieces are ready
00:03:34 and the integration works. So you can do even that test-driven
00:03:37 on this higher level. And basically make sure, however,
00:03:41 if you do it in the before or after, when the pieces are together and everything works together,
you
00:03:45 want to have an automated test that proves it. So it leads to the first point.
00:03:50 You need to plan the development of integration, or acceptance tests, whatever they're
00:03:54 called in your environment, as part of development because it is something that takes time.
00:04:01 So I would remember it. I would also put it as part of the done criteria.
00:04:04 When you have a higher-level user story that says develop this and this and cover those
cases,
00:04:10 then the test must be an automated test. It must be included to prove that it works just the
same way
00:04:15 as on a unit level. And then we come to the second part, to run this continuously.
00:04:20 So imagine if you have all these tests, but you develop all the time.
00:04:25 If they don't run, they don't give you any information. So then they're actually worthless.
00:04:29 And if they break, you want to know right away. Because sometimes it's like building on a
weak foundation.
00:04:35 You build more and more, and then you find out, oh, I broke something, and now I have
00:04:39 to revert back the whole thing. So continuous integration means to have all the unit
00:04:46 tests, but also the integration tests, to run continuously. Now in some systems, like in the Java
environment,
00:04:53 that have a slightly different architecture, it means that when somebody submits a change,
then
00:04:58 there is a test running to make sure that this new change doesn't break the existing tests
00:05:02 or the tests that were added. In ABAP, we have this one live system
00:05:06 that's running all the time. So you make the change, you activate it,
00:05:09 and maybe you can run your little case. You run your unit tests.
00:05:12 But then what should happen? So the set of integration tests should work all the time
00:05:19 and they should be run. And the question is now, where?
00:05:23 In a development system, you can do it. But then sometimes when you're working on things,
00:05:28 they will be read. And you have to make sure, is this my problem?
00:05:30 Is it somebody else's problem? Often, the better way to do this is to say,
00:05:34 when the code goes into the first test system level, wherever new code gets in, you can run it.

00:05:43 But you can also schedule, and you should schedule tests in your development system.
00:05:50 Basically, regularly, say every hour or something, run all the tests that you have for your team.

00:05:55 And then you make sure what we build, and what we give to the outside world and other teams
using us,
00:06:00 our APIs, is always running. And that's called the main line.
00:06:04 The main line is all the code that we own, that we provide, that is supposed to keep running all
the time.
00:06:10 Just a little story to show how powerful this can be. There can be one team that develops and
develops.
00:06:19 And then after eight weeks of developing, they start testing. And everything's a mess, and you
need four to six weeks
00:06:24 to stabilize that code. That's one way to do it.
00:06:27 Another team, and this is a real story, they worked very much in this way, and had
00:06:32 all the tests and integration tests fully automated. And in the development system they
00:06:37 could do during development, they could do live demos for customers,
00:06:42 and there was no runtime error. Because all the cases that they cared about,
00:06:46 they were running all the time and being tested all the time by automated tests.
00:06:52 And this also prevents you from another productivity killer. It's that you make a mistake that
somebody else gets hurt,
00:06:58 and they have to find out and analyze it, find out, oh my problem that I have it's not mine.
00:07:03 It's somebody else's. And they have to call you, and you're not there.
00:07:06 And a lot of time gets wasted this way. So you see that the benefits are clearly there.
00:07:14 It's an important element. Otherwise, everything else we did loses a lot of power.
00:07:20 So you have to have those integration tests run regularly.
00:07:23 So one way to make that sure is, of course, you have to run your tests all the time.
00:07:27 And to do that, you use the ABAP Unit Runner, the report name you can see there
RS_AUCV_RUNNER,
00:07:34 and it runs all your unit tests. And you can schedule it.
00:07:37 So you can really run it all the time, every hour for instance. Another way to do it is to run it via
the ABAP Test Cockpit.
00:07:43 Because all the unit tests-- well , they are technically unit tests, even though they may be
00:07:47 integration tests semantically-- you can trigger via that as well.
00:07:51 Either way, it's good to do this. And you need to run it that way.
00:07:59 And, of course, what's important is that when a test fails-- so even if they run, they, of course,

00:08:03 run automatically. But you're not triggering it and waiting for the result.
00:08:06 So when anything goes wrong, you have to get a mail immediately, and you have to find out.
00:08:11 So the Unit Runner can send mails in case of errors. And the mails should be going to the
whole team.
00:08:19 Because sometimes you don't know who was it, and everybody has to take care of it.
00:08:24 So it's a team responsibility. And therefore, we recommend to use a distribution list,
00:08:29 and let the mail go to the whole team. Now, there can be a problem that sometimes you
00:08:36 have so-called false positives, meaning that a positive test means I found an error.
00:08:41 And then you look at it and say, oh, it wasn't really an error at all.
00:08:44 Because the next time I run it, it works again. I don't know why.
00:08:48 That's called an unstable test when it has a hidden dependency on something
00:08:54 that you didn't control. And therefore, somebody changed, for instance, the configuration
00:08:59 or whatever, and suddenly your tests run, or they don't run anymore.
00:09:03 Those are unstable tests. And actually, those are worse.
00:09:06 It's almost worse than having no tests because they give you basically a negative return on
investment
00:09:15 on tests. Because you have to analyze them.
00:09:17 And then if this happens a few times, people will say the tests are not good,
00:09:21 automation is not good, it's too much work, we don't have time, and then the whole thing will
go down.
00:09:27 So one very important thing is to make sure tests are stable, meaning that you have no
dependencies
00:09:34 that you don't control. And if a test goes red, it has to be
00:09:39 because it found an error in your code or in whatever code it tests.
00:09:44 So that's very important. So you need to take the time to make your tests robust,
00:09:49 meaning not flaky. There's different words of saying that.
00:09:53 And if there is a problem, then provide the details in the error log so it's easy to understand
00:09:58 and analyze what's wrong. And like I said, unstable tests kill the automation benefits.
00:10:03 One, because you have to spend the time to analyze. But actually worse is because you
basically
00:10:10 say all this effort we put into automation, it doesn't give us the ROI that we want.
00:10:14 And this is, of course, a bad thing. So I hope you understood the key elements
00:10:20 of continuous integration. Number one, you have to have the integration
00:10:23 tests in the first place. Number two, you need to really make sure and run them
00:10:27 all the time by a scheduled run, or by ATC, and make sure the tests are stable.
00:10:32 And then you get the maximum benefit out of your automated tests.
00:10:37 This was it for this unit. And we'll see you in the next unit.
Week 6 Unit 4

00:00:08 Welcome back to Week 6 Working with Legacy Code, Tools, and Summary
00:00:13 And this is our last unit, Unit 4. And that's basically the summary part,
00:00:18 and it's titled "What to Focus on When Writing New Code or New Features."
00:00:28 So what are the key topics when you are writing testable code? So these are only the
headlines.
00:00:37 We will have separate slides for each of them. And first of all, we want to talk about the
constructors
00:00:43 and the collaborators. What's collaborators?
00:00:45 That's our depended-on components, so don't worry. It's nothing new.
00:00:50 And then we will talk about statics and global state-- about design principles.
00:00:56 Here is the "SOLID" principle. We will show you what this means.
00:01:00 And then we also want to show you what it means digging into collaborators.
00:01:07 The Law of Demeter-- what to do and what not to do there. So where are we coming from?
00:01:14 Remember the very first slide you saw where we had this scale.
00:01:18 On the one side we had "Write testable code," and on the other side we had our tests--
00:01:24 our automated tests. And during the whole course, we learned that they both
00:01:32 definitely go together. One cannot live without the other.
00:01:35 And we were mentioning many things on the way. Some things we might have mentioned in
the video but they
00:01:48 were not on the slide. So what you see now is a summary and also
00:01:53 some things where we think we did not emphasize it yet enough so we bring it.
00:01:59 Right. And we also have new stuff.
00:02:05 Let's look at the summary points and put it all together. Yeah.
00:02:10 OK let's jump right into constructors and collaborators. All right.
00:02:16 So first of all, collaborators. It's a new term but we used it on purpose
00:02:22 because if you go to Google and look at their material-- and they also have a lot of stuff
00:02:27 about this stuff-- writing testable code and Misko Hevery was one guy that we mentioned
earlier--
00:02:31 this is how he calls it. In our environment, we call it "Depended-On Component"--
00:02:36 DOC, or whatever. But it's the same thing.
00:02:38 And so this worrying about dependencies is really what it's all about.
00:02:46 So what are the main points that we can take away from everything we learned?
00:02:49 So when you write new code, you want to make sure you don't make it worse, right?
00:02:53 You have, sometimes, legacy code-- and then you have to deal with and you know
00:02:56 after the fact at installation. But when you write new code, do not
00:03:01 create dependencies directly, especially in the constructor-- or anywhere else in a method,
really.
00:03:08 Basically, create your own dependent objects. But if you have a significant depended-on
component-- meaning
00:03:14 it's not just a library class that everybody uses and it's really nothing special.
00:03:19 It's a very low-level component. That's not a problem.
00:03:22 But if you depend on something big from another team, from another unit, whatever, that you
00:03:29 want to isolate against then you have to isolate against it either through injection
00:03:34 or through a factory. So keep in mind when you write new or create
00:03:40 object you should shrink back. Yeah, is it the right spot where you're doing that?
00:03:44 Exactly. And what is it I'm creating?
00:03:46 So some things are system-level classes-- no problem at all. But other dependencies to other
components and services
00:03:53 is a problem. The next thing is, of course, provide
00:03:56 if you do that provide injection mechanisms or dependency lookups on how to deal with this.
00:04:03 And so what's good for new code? Constructor injection backdoor we use only
00:04:08 really for legacy code and services when it doesn't work the other way.
00:04:13 And when you have a legacy code situation where you have many places, maybe, and you
need to change and slowly
00:04:18 add testability, dependency lookup is really the best way to go because it's very low risk.
00:04:23 And you make only one little change-- you change a create object with a factory call
00:04:27 but there you come independent. So it's a good way to provide an injection mechanism that
way.
00:04:33 The only hurdle you have here is that's not your own decision. So if you start using factories
then
00:04:39 you need the buy-off of your team. That's not something you can do in your little corner
00:04:44 and oh, yeah-- I created a factory and they all have to use it.
00:04:49 That's something you should discuss within the team. Once you have an agreement, then you
are good to go.
00:04:55 Yeah. Well, that's actually a very important point,
00:04:57 this whole team aspect we will come back to in the end in our little goodbye part of it,
00:05:02 but it's a very important thing that whatever you do here, you need the whole team to agree on
it and to do this as a team
00:05:07 because otherwise there is no synergy, right? If you can't write testable code just for yourself
00:05:12 then other people will wonder, what is this, and then you don't have the benefit from it.
00:05:17 But we'll come back to that. And we already said public APIs-- please, via interfaces.
00:05:24 Anything you offer to the outside world, it's definitely the way to do it,
00:05:27 so that clients can easily write their own test doubles. The clients even can be your colleagues.

00:05:33 It's not only the customer-facing interfaces, it's really everything which faces
00:05:39 anyone outside of your team. Right.
00:05:41 And even inside your team-- maybe your team is big enough so that it even makes sense
there.
00:05:48 Right. So it's a matter of judgment but really, interface
00:05:51 is a very good thing to decouple. And if you are insecure on "Should I use
00:05:54 an interface or not?"-- use it. That's the easiest rule.
00:05:57 Make it for all your classes. Create an interface.
00:06:01 And once you are more experienced and see, OK, in this case, I don't really need it,
00:06:06 then you have evolved. Then you have more knowledge about that,
00:06:11 and then you can say, OK, here I can leave it out. If you're not really sure, then just create
00:06:17 one because it doesn't cost anything-- either performance nor it's not a lot of writing.
00:06:24 Right. In fact, if you kind of-- oh, I started with a class,
00:06:27 what do I do? It's very simple to change.
00:06:29 Just take whatever is in the public section, put it in an interface, that's it.
00:06:32 And write interfaces statement, and you have to go through a factory anyway, right?
00:06:36 So that's already everything it takes. You just copy out the public section,
00:06:40 and it's very easy to change, and you have, then, the benefits from it.
00:06:43 And actually, if you're using Eclipse that's supported. That's a supported factory.
00:06:47 And so if you have an interface, then just use the quick fix Control-1 and it offers you to pull up

00:07:00 everything which is in there, and then it's done. So you don't even have to do it by hand.
00:07:05 Right. OK, so now we come to the next section of topics--
00:07:10 data. Yeah.
00:07:12 So-- global data. We mentioned the ultimate global data already--
00:07:16 the database-- but there is other global data. The global data is the enemy of testing
00:07:24 because within that global part easily dependencies can hide and are not seen right away.
00:07:36 And therefore, you should avoid everything which is global and keep it to the bare minimum
you really, really need.
00:07:42 And that is within reports the global variables, for example, and the same in function groups or
even worse,
00:07:51 if you have shared includes and they are really global these variables in there, but also within
classes.
00:08:01 Really think about, do I need static variables, really, in the class?
00:08:06 Do I need this as a member variable, really? Is it connected to the core of the functionality of
that class
00:08:16 or not? That also defines if it should be a member variable or not.
00:08:23 Yeah. So be as local as possible.
00:08:27 That's the golden rule here. And then also configuration or customizing--
00:08:32 that's another place where you'll find a lot of global settings.
00:08:36 Yeah-- global things. And then the database-- we mentioned that already.
00:08:41 And the static methods and static classes-- try to avoid them.
00:08:48 We saw an example of where it might make sense to use it. It was the factory and the injector
of the factory.
00:08:55 But other than that, classes you really need to test. Static hinders you to do that and so we try
to avoid it
00:09:05 and it's not a lot of hassle to do that. Even if you have a service class which
00:09:10 has no member variables at all, so no memory at all, basically--
00:09:15 even then it's easy to create an instance-- Create an instance and work with the instance
00:09:23 because then you can inherit from it, you can override things, or pull out
00:09:27 the interface to be able to substitute things. Yes testing and things.
00:09:33 It's just worth doing here because once something is static, it's hard to change that afterwards

00:09:39 when there are a lot of places already using this class. So that's global.
00:09:45 Try to avoid it. Keep everything as local as possible.
00:09:52 OK, but-- maybe the damage is already done, yeah? We have that global stuff lying around.
00:09:59 So what to do? How to deal with that?
00:10:04 And then-- if, for example, if you have customizing or configuration
00:10:10 that has to be somehow global. But don't leave the attributes lying around
00:10:17 and everyone just accessing the attributes. Put someone in front of this global stuff to manage
it,
00:10:23 and then it's no longer that global because then everyone has to go through a defined interface

00:10:30 and you have one code which is managing all of that global stuff.
00:10:34 For instance, one class by which you access all your customizing.
00:10:38 And then you can easily switch that in tests. Yeah, and then you just replace a class with a test
double
00:10:44 and then you are fine because then in your test you can give back to your code under test
00:10:51 whatever is necessary for that specific test. If the code under test would access directly the
attributes,
00:10:58 you wouldn't have the chance. Again, we mentioned that in the context of the factory
00:11:05 a class should not enforce the singleton-ness on its own but someone who decides what
context is this class now
00:11:13 in should do that. And we showed you that it should be the factory deciding that.
00:11:20 If you don't have a factory yet, then someone else has to do it. But if you have a factory,
definitely the factory
00:11:25 should do that and not the class itself. For database content, we are good to go
00:11:35 since we have that Open SQL test double framework, so that's a really nice way to get this
global data out
00:11:44 of the way during testing. So that's a big help here.
00:11:52 Then integration tests and database content-- also we've connected together with the OSQL
test double
00:12:02 framework so you set up everything you consider to be there during your test in the database

00:12:09 and then your test only sees what you want this test to see. And there's no distraction and also

00:12:20 no interaction with other things currently running on the system.


00:12:25 And then also make sure-- or you automatically make sure by doing that--
00:12:32 that tests do not interact on the database with each other because they are separated because
everything is doubled.
00:12:39 But if you don't double-- meaning you don't use the OSQL framework--
00:12:44 it's also possible to write things really to the database, run the test, and then delete it
afterwards.
00:12:48 Or, every test writes its own thing, own IDs, and works only with that.
00:12:55 That's also possible. But always take care that tests do not interact
00:13:00 and are not depending on any order of execution. That's really, really important.
00:13:05 So here, also, golden rule-- avoid global data if possible.
00:13:10 And if not, be really careful. Yeah, well especially, I think, for integration tests
00:13:14 when you have many classes and they use maybe 100 tables underneath, you can't go in
00:13:19 and say, oh, I'm going to replace all the tables. It's just not realistic.
00:13:23 For that case, you really have to think "How do I make sure that I don't destroy something
00:13:28 on the database?" So in the class setup maybe, you have some code that checks
00:13:33 do I have a client, or do I have a key that has some kind of a discriminator-- this is test
00:13:38 data, don't take it serious. And then an ID. Even the best case is
00:13:43 that two people can run the same tests at the same time because you have to think about it--
00:13:49 two people develop in this space. They want to run the integration test on a higher level
00:13:55 to see that whatever they did didn't break anything. And then this test meets--
00:14:00 those two test runs meet on the database at the same time. And so if you have integration
tests that touch the database,
00:14:07 you should think how to separate them on the database level as well.
00:14:11 Otherwise, you get all kinds of very, very tricky things. And again, if you have trouble with tests
you think,
00:14:16 "Oh, it's not worth it," and then tests get a bad reputation.
00:14:20 So that's all about global-- avoid it, if possible.
00:14:24 That's the baseline here. We mentioned this--
00:14:29 SOLID principles. So what does SOLID mean?
00:14:32 So it's an abbreviation here. The first letter of all these rules here.
00:14:39 And we are talking here about good design principles. So it's nothing invented here.
00:14:43 That's common knowledge. Some principles on this slide might be known to you.
00:14:54 We were focusing on the last one, or the "D" one-- Dependency Inversion Principle.
00:15:01 Interfaces-- also the factory-- everything was playing into that.
00:15:06 So your code should always, always work with abstractions, never with the concrete thing.
00:15:13 Meaning-- working with interfaces and not knowing which classes are implementing that
00:15:17 because at the moment when you know that, you're depending on it.
00:15:22 And we don't want that. And also, if you think about class sizes,
00:15:29 many classes are way too big. They do far too many things.
00:15:33 That's the first one here-- Single Responsibility Principle.
00:15:37 One class should do one thing and one thing only. This is really good.
00:15:42 And if you adhere to that rule, then testing is also much easier because your class has a single
focus
00:15:48 of what it should do. And then it's also much easier to write a test for it
00:15:52 because it's clear what to test because the task of that class is clear.
00:15:57 And there's a nice trick to check for that. Just ask the developer, "What does that class do?"
00:16:05 and when he starts talking, and says, "Yeah, this class does this and--" OK, he loses.
00:16:09 There should be no "and" or no "or" because if he uses that, then the class does more than
one
00:16:16 thing, and that's not good. It takes some practice to really get there
00:16:23 but challenge yourself, or challenge your colleagues. It's really worth it.
00:16:28 The small classes are much easier. I mean, the "and" challenge is a nice little way
00:16:32 to elicit that-- is it obvious or so-- but we have to say that good OO
00:16:37 design-- object-oriented design-- is somewhat-- I wouldn't say it's called an art,
00:16:40 but something that takes a little bit of practice. And the SOLID, what that means in-depth is
beyond the course--
00:16:47 at all beyond the scope-- but it's worth looking into.
00:16:50 So if you haven't done this, you should really look into object-oriented design and this
00:16:57 leads to an article and a video by Michael Feathers. There is a close relationship between
good design
00:17:06 and testability. And actually striving for testability also
00:17:09 basically breaks up dependencies and brings you to good design. So there we have the scale
again--
00:17:15 that good tests and testability that we have as a goal also influences design and breaks up the
code
00:17:22 into the right logical units. Right.
00:17:26 So there are many factors playing into that scale. It's not really that two-dimensional scale
00:17:30 we draw there. Everything is connected with each other,
00:17:34 and this is just another aspect to it. These are links, so once you have the material,
00:17:41 you can click on the links and read through that. Finally, the Law of Demeter.
00:17:48 This is not so well-known, but it's also an important thing. Basically avoiding to create more
trouble for yourself
00:17:57 or be aware of a kind of a hidden danger, if you will when you design code.
00:18:06 And an interface for all classes is not enough. And there is this Law of Demeter that
00:18:12 explains what else there is, and we drew a little example here
00:18:15 on how to explain this. So let's assume you're writing a program,
00:18:21 and you're simulating a dog and a dog owner. And so you have a dog that has a head, and a
mouth,
00:18:27 and a tongue, and they're different objects, right? And of course it doesn't make sense,
00:18:31 but we'll just do a silly example. And then at the end of this chain, at the tongue,
00:18:37 there's a method called "Bark." And so now the client code, the one who uses this dog object,
00:18:44 they want the dog to bark. So what do they do?
00:18:46 They get first-- from hopefully a factory-- they get a Dog object.
00:18:50 And then they say get the head, get mouth, get tongue, and then they say bark.
00:18:54 And so now you think, OK well, I'm done. Good, good-- I did it.
00:18:59 You got the dog to bark. But what else did you do?
00:19:02 Now the internal structure of the dog-- the classes and their connections
00:19:07 and the relationships-- you know, the reference structure, basically-- is exposed to the client
code.
00:19:13 And basically, the dog spilled its guts, if you will, to the client.
00:19:18 Now if you want to refactor the dog and change-- like, put the tongue and the mouth together,
00:19:24 it didn't make sense to separate it or something. You can't do it easily because then the client
00:19:28 has to change the code as well. And so, by exposing this, you nail down
00:19:34 the internal structure of this class-- not just a class, but a small little package or something--
00:19:39 a few collaborating classes. And just imagine if you have 10 classes that work together
00:19:45 to do something, and this is a practice that people do, and one calls this way so this
connection of dependencies
00:19:53 is nailed down by the client. The other calls that way.
00:19:55 The other calls that way. Then, basically from all ways, the whole thing is basically
00:20:00 suddenly concrete because you cannot change anything without breaking the client.
00:20:05 And that's of course very bad. So you want to be able to change your internal workings.
00:20:10 And then, if you have a module-- a service-- that exposes anything to the outside--
00:20:15 don't give internal objects out, ever, unless they really are logically necessarily part of the API.

00:20:22 So what does this mean? The solution is easy.


00:20:28 Whatever you want to expose, put it to the outside-- to the perimeter.
00:20:33 So the dog itself gets a bark method. And so for instance, if you have another case where
00:20:42 one service calls another and they use internally something and they give--
00:20:46 you make a call, you get that other reference as a return value or anything.
00:20:51 It's a smell. It's something dangerous.
00:20:53 Because now you know, as a client, that this service is using another service
00:20:57 and it gave you the reference and maybe that did some configuration.
00:21:00 Now you try to reuse it-- it doesn't work.
00:21:03 You're hitting dependencies to other things. So it's very bad.
00:21:08 Basically, the point is-- it's not so easy to see, but basically-- if ever you have this kind of code

00:21:15 there with those sequence of arrows, you should get a warning light.
00:21:20 Now, there is one case where this is allowed, and actually very good, and that's
00:21:25 the so-called Builder pattern. So if you say--
00:21:28 where did we have this case? We saw that when we had our ABAP test double framework.
00:21:33 Right. And remember this configure call?
00:21:35 There were also this arrow, arrow, arrow-- this was the Builder pattern, always
00:21:40 returning the same object. Always returning the configuration object.
00:21:45 No one was digging into some object hierarchy, it was always the same object, so you could
also
00:21:50 write a Builder pattern just in separate lines. Right.
00:21:54 So basically, when the class is the same that walks-- goes through-- flows through the
sequence
00:21:59 it's not a problem. But if you have different classes that flow through,
00:22:02 that come from inside of that component you're calling, then that's a bad thing.
00:22:09 And in fact, if you provide a component, you should totally avoid that.
00:22:12 That's a really bad design flaw. If you're using a component, what can you do?
00:22:17 Well, if you notice somebody has this API, then at least what I would do is to say,
00:22:22 I'm not going to do that directly, but I'm going to write my own little class.
00:22:25 Let it do it. But if they later are smart enough to move that method,
00:22:30 I don't have to change all my code. So dependencies I have to another component I
00:22:36 would like to collect on one-- I don't know, an interface class sounds strange--
00:22:41 but basically, that encapsulates-- A delegation class.
00:22:44 --delegation class to that component. So when something changes behind that, and maybe the
design
00:22:50 wasn't so good, then I am isolated against. And sometimes things happen, like there's
00:22:55 a new version of this, or some change coming-- then you only have to change this place,
00:22:59 and not 10 other places in your code. We should mention one more thing,
00:23:03 and that is now we want to test something like that. And if you want to test it and you have a
factory, OK--
00:23:09 with the factory multi-level test-- that's a multi-level test here--
00:23:13 you would replace the getTongue for example, here. And then your test would go.
00:23:18 So with a factory, it's not that hard, but still, you are depending on that this getTongue does not

00:23:24 get suddenly refactored away from you. But if you don't have a factory, you
00:23:32 have to have a test double for the dog, for the head, for the mouth, and the tongue and inject
that all
00:23:39 before that, so it's a lot of effort to do that. And you also don't want that because it doesn't
bring you
00:23:44 any benefit. Just because they need you to go down all this object hierarchy
00:23:51 just to make the dog bark-- I mean, no dog owner goes to his dog and says, tell your head,
00:23:58 tell your mouth, tell your tongue that you bark. They say, bark.
00:24:02 And interfaces should be more natural. Right.
00:24:06 So of course, this was artificial. But I think the point is, beware of those exposing
dependencies,
00:24:12 and I think you got the point here. It's important to not make things worse.
00:24:17
00:24:19 And that makes the end of our course. But I guess we want to give you some--
00:24:25 Final advice. --final advice.
00:24:26 And maybe start with that. Practice, practice, practice.
00:24:34 Just by listening to us, you now got a lot of input. But in order to internalize that, you need to
practice.
00:24:43 And also don't be afraid if you feel a little bit, oh I don't really know how to do that,
00:24:48 but I'm a good programmer, but-- I don't want to do that.
00:24:54 Yeah. Programming or developing tests is
00:24:59 different than developing the production code. There's a different kind of thinking necessary,
00:25:04 and that needs practice. Just go for it.
00:25:07 If you are a good programmer, you will be very, very soon a good test developer also.
00:25:13 Just go for it. Or testable code developer.
00:25:15 Yeah, testable code developer, right. Yeah, the point is--
00:25:17 the learning curve, it feels strange to me especially when you're already totally mastered
00:25:21 all your environment and your tools and now this strange thing comes along,
00:25:25 so it's an emotional barrier-- I don't feel like I know what I'm doing.
00:25:28 But it's totally worth it. And I would say it's--
00:25:32 compared to everything you know about programming and the domain you're working in and
everything
00:25:37 it's like tons and tons of knowledge, and this is maybe a fraction of a percent, if you will.
00:25:43 But it can have a huge impact. I'm talking way, way more than 20%
00:25:47 or 50% on productivity of a team. So if you compare that little special knowledge that
00:25:53 takes a little practice to get internalized, it can have a very great benefit.
00:25:57 So it's worth it. That's what we're saying.
00:26:00 OK and then test-driven development-- seems hard.
00:26:03 Sounds silly at the beginning. But I think you got the twist of why this is really useful.
00:26:10 And even if you don't practice test-driven development in your daily life, try to strive for it.
00:26:18 Try to be as close as possible. That also means write your test timely--
00:26:26 not oh, we do it in the next sprint, or in the next week, or next release.
00:26:30 The development is over when test and production
00:26:35 code is written, and not only the production code. Right.
00:26:39 I mean, we don't want to be super strict, sometimes it's really strange to write the tests first
when you have to,
00:26:43 for instance, do some major refactorings and five things have to change.
00:26:47 But the point is-- almost-TDD is also good,
00:26:51 but the point, I think, when you have the routine you will see that the test-driven part really
00:26:56 drives the design, and the design is what really matters then for testability to make tests
00:27:01 and further development easy and faster and that's the whole point.
00:27:04 Right.
00:27:05 And then we talked about pair programming. Yeah, pair programming-- give it a try.
00:27:10 Talk to your colleagues about it. You know all the benefits.
00:27:15 Go back to the video if you forgot about it. Show the video to your colleagues
00:27:19 if they ask you about, what is it? Let us explain to them.
00:27:24 And go for it. Try it.
00:27:27 It's the best code reviewer you can get because it's right on the spot.
00:27:32 And then use modern tools. Go for Eclipse.
00:27:35 Go for ABAP in Eclipse. Let the tool help you.
00:27:38 Remember Control-1. That's your friend.
00:27:44 And all the frameworks too. I mean, ABAP in that way actually
00:27:47 has stuff that other languages don't have because we have this tight SQL integration.
00:27:51 We have the Open SQL test double framework, the CDS test double framework, so that
makes it even--
00:27:57 the database testing much easier than in other environments. So you're lucky there.
00:28:02 And also with these modern tools, refactoring is much easier because the tools support you
with that.
00:28:09 And you should do it because it makes the code cleaner. And that's another thing-- clean code
and clean design,
00:28:18 they go hand-in-hand. And refactoring-- just remember only when the tests are green,
00:28:26 don't change functionality during refactoring. Always split these activities
00:28:32 into different time slots because when you do refactoring you don't want to change the code.
00:28:39 And-- At the end--
00:28:41 --just do it. Go for it.
00:28:43 And enjoy. Enjoy.
00:28:45 Yeah. That's the fun part.
00:28:47 We mentioned it at the very beginning. Once you are in this routine, it's
00:28:51 really fun to see your tests stay green and get green. It's really satisfying, and you should go
for it.
00:28:58 Don't miss out on that. And you avoid a lot of trouble that you'd otherwise
00:29:02 have debugging and stuff. Yeah.
00:29:05 So also this week, we will have a weekly assignment. So you can use the forum if you have
questions
00:29:12 and want to talk to other students. And then after this week, there will be the final exam.
00:29:20 We wish you luck for that. And you are well prepared, so don't be afraid.
00:29:25 It's not too hard. And then just go for it.
00:29:30 Thank you very much for listening to the whole course. I hope you enjoyed it.
00:29:34 We truly enjoyed making it. Because we really believe in it.
00:29:37 We have a lot of experience in this. This is good stuff and I hope it will make your life
00:29:42 as a developer better. Then, see you.
00:29:48 See you.
www.sap.com/contactsap

© 2018 SAP SE or an SAP affiliate company. All rights reserved.


No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP affiliate company.

The information contained herein may be changed without prior notice. Some software products marketed by SAP SE and its distributors contain proprietary software components of other software vendors.
National product specifications may vary.

These materials are provided by SAP SE or an SAP affiliate company for informational purposes only, without representation or warranty of any kind, and SAP or its affiliated companies shall not be liable
for errors or omissions with respect to the materials. The only warranties for SAP or SAP affiliate company products and services are those that are set forth in the express warranty statements
accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty.

In particular, SAP SE or its affiliated companies have no obligation to pursue any course of business outlined in this document or any related presentation, or to develop or release any functionality
mentioned therein. This document, or any related presentation, and SAP SE’s or its affiliated companies’ strategy and possible future developments, products, and/or platform directions and functionality are
all subject to change and may be changed by SAP SE or its affiliated companies at any time for any reason without notice. The information in this document is not a commitment, promise, or legal obligation
to deliver any material, code, or functionality. All forward-looking statements are subject to various risks and uncertainties that could cause actual results to differ materially from expectations. Readers are
cautioned not to place undue reliance on these forward-looking statements, and they should not be relied upon in making purchasing decisions.

SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE (or an SAP affiliate company) in Germany and other
countries. All other product and service names mentioned are the trademarks of their respective companies. See http://www.sap.com/corporate-en/legal/copyright/index.epx for additional trademark
information and notices.

You might also like