第 336 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
developers can submit the code back to the central repository and commit their
changes. The changes can be synchronized by other developers into their local repos-
itory and continue working on their part independently (see Figure 9.1).
Remote Repository
SAP Web IDE Local SAP Web IDE Local SAP Web IDE Local
Repository of Developer 1 Repository of Developer 2 Repository of Developer 3
Figure 9.1 Shared Repository Concept for Projects Using Git
Unlike other version control systems (VCSs), Git tracks the changes as snapshots. In
other words, it doesn’t just track new file changes in each version, but rather it stores
a snapshot of the entire project status every time a new change is pushed to its repos-
itory. In Figure 9.2, you can see how Git stores the snapshots; the rectangles with dot-
ted lines means those files haven’t changed in that version, so it references the file to
its previous version.
Version 1 Version 2 Version 3 Version 4
File A File A1 File A1 File A1
File B File B File B1 File B2
File C File C1 File C1 File C2
Figure 9.2 Git Snapshots Approach for Project Status
336
第 337 页 / 共 465 页
9.2 Git Basics
Now that you have a basic understanding of Git, let’s start with building a repository
and linking it with our already-created projects. We could have taken an alternative
approach by creating the Git repositories prior to the creation of the actual apps in
the previous chapters, but for our examples, we decided to link the apps in SAP Web
IDE with a Git repository after the completion of the apps. You can take either
approach. If you’re the one who is setting up the initial version of the app, then you
can take the approach of creating a repository later. If there are multiple developers
from the start of the project, then it’s necessary to set up the initial remote repository
first, clone the blank repositories to the SAP Web IDE for each developer of the proj-
ect, and then start working on the app. Figure 9.3 provides a high-level overview of
the steps to set up the Git for the projects.
Create Blank Initialize the Commit the
Link the Local
Remote Projects in SAP Source Code to
Repository with
Repositories Web IDE with a the Git Remote
the Remote Git
in GitHub Local Repository Git Repository
Figure 9.3 Git Project Repository Setup Plan
9.2.1 Creating Initial Project Repositories Using GitHub
First, you need to set up an account at https://github.com. On the GitHub home page,
click on the New Repository button on left side of the page, as shown in Figure 9.4, to
set up an initial blank repository for the project.
Figure 9.4 Creating a New Repository in GitHub
337
第 338 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
In the next screen, give the repository a name (for this example, enter “PurchaseDoc-
umentsALPRepo”) and description. Check the box for Initialize this repository with a
README, and click on Create repository, as shown in Figure 9.5.
Figure 9.5 Setting Up and Initializing the New Repository
In the next screen, you can see that the repository has been setup. Now click on the
Clone or download button, and then click on the Copy icon to copy the URL as shown
in Figure 9.6.
338
第 339 页 / 共 465 页
9.2 Git Basics
Figure 9.6 Copying the URL for the Git Repository
9.2.2 Initializing the Local Repository for the Projects in SAP Web IDE
After you’ve set up the initial remote repository, open the SAP Web IDE and right-
click on the project. Then go to Git (cid:2) Initialize Local Repository, as shown in Figure 9.7.
This will create a local Git repository with a default master branch for the project. This
will act as the primary repository for further developments until we push changes
back to the remote repository.
Figure 9.7 Initializing a Local Repository for the Project in SAP Web IDE
339
第 340 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
9.2.3 Linking the Local Repository with the Remote Repository in GitHub
Now, let’s link the local repository with the remote repository, which we created using
GitHub. Right-click on the project, and go to Git (cid:2) Set Remote, as shown in Figure 9.8.
Figure 9.8 Linking Local Repository with the Remote GitHub Repository
In the next popup window, enter the URL of the remote repository that we copied
from the GitHub project earlier, and then click on OK, as shown in Figure 9.9.
Figure 9.9 Configuring the Git Repository Using the Git URL in SAP Web IDE
In the next window, as shown in Figure 9.10, click OK to confirm the changes fetched
from the remote repository branch.
340
第 341 页 / 共 465 页
9.2 Git Basics
Figure 9.10 Changes Fetched from the Remote Branch in Git
9.2.4 Submitting Code to Repository (Stage, Commit, Push)
Before we commit changes to the Git repository, you need to understand some of the
basic concepts in the SAP Web IDE related to Git integration. Let’s take a quick over-
view of certain parts of the SAP Web IDE that you’ll need later in the chapter to work
with the repositories.
In Figure 9.11, you can see that when you click on the Git Pane icon on the right side
of the SAP Web IDE project, a bunch of icons appear that are related to Git.
Git Pane
Figure 9.11 Git Pane in SAP Web IDE
The icons are described as follows:
(cid:2) Pull
As a combination of fetch and rebase Git actions, this icon fetches any changes
from your remote repository branch and combines those changes with your local
branch in the SAP Web IDE.
341
第 342 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
(cid:2) Fetch
This option fetches the changes it detected from the remote repository and lists
those changes for you; however, it won’t apply those changes to your local branch.
(cid:2) Rebase
In addition to the remote/master branch, you might have to create additional
local branches based on the projects requirement, which often leads to conflicts in
the code in different branches. This is where the Rebase option becomes helpful, as
it will make the Git temporarily discard the changes in the local branch, update the
code from the remote branch, and then try to apply the local changes again in the
correct order. This will help you when your local changes are having conflicts in
the remote repository or when you want a new change in the remote branch to be
added to your local branch without losing the local changes on the project. Rebase
will also rewrite the project commit history for a cleaner project history (see Fig-
ure 9.12, in which the different commits in remote and local branches are repre-
sented by a square and triangle, respectively).
Before Rebase After Rebase
Master Remote Feature Local Master Remote Feature Local
Branch Commit Branch Commit Branch Commit Branch Commit
History History History History
Figure 9.12 Git Rebase Concept
(cid:2) Merge
This option works like Rebase but in a slightly different way. For example, you
might need some of the new changes submitted in the remote branch from a local
342
第 343 页 / 共 465 页
9.2 Git Basics
repository for a new feature (you might have opted to create a new feature branch
in your SAP Web IDE just to work on this feature and need some of the changes
from the master/remote branch to be incorporated into your local branch). The
Merge option creates a merge commit to your local branch by combining the his-
tory of both the branches together and thereby merging the commit history of
both branches (see Figure 9.13).
Before Merge After Merge
Master Remote Feature Local Master Remote Feature Local
Branch Submit Branch Submit Branch Submit Branch Submit
History History History History
Merge Commit
Figure 9.13 Git Merge Concept
(cid:2) Apply Stash
This option is useful when you’re working on your local branch on a file and decide
to switch to another local branch to work on a separate feature for your project,
but you don’t want to commit the current unfinished changes back to the remote
branch. Instead of submitting the changes to the remote branch, the developer
can use the Stash option to temporarily store the uncommitted changes and then
switch to a different local branch without losing those changes. After the devel-
oper is done with the work in the other local branch and switches back to the local
branch of the uncommitted code, the code can be retrieved using Apply Stash but-
ton from the Git pane.
343
第 344 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
(cid:2) Reset
Like the name says, this option resets all the uncommitted changes from the local
branch in the SAP Web IDE. Reset can be done as a mixed reset or as a hard reset. A
mixed reset resets your files from the staging area and reverts back to the original
commit history of your remote branch, but your local changes are still available in
files. A hard reset resets the commit history, removes files from the staging area,
and removes all the local changes you’ve made in your workspace. Basically, it will
put your workspace in sync with the last committed state of its respective remote
branch.
Next, you need to become familiar with the staging area of the Git pane in the SAP
Web IDE (see Figure 9.14). The staging area is where the local changes in the project are
tracked by the SAP Web IDE, and the user has the option to commit the files into the
remote repository from the staging area or discard the changes and revert to the orig-
inal code. By checking or unchecking the checkboxes for each file you determine
whether the files are committed or not.
Staging area
Staging options
Uncommitted files in the local branch
Figure 9.14 Staging Area in SAP Web IDE Full-Stack
Just below the staging area’s list of changes that are tracked, there is a text area to
type in the comment for the commit and the options to Commit, Commit and Push,
344
| Staging area Staging options Uncommitted files in the local branch |
|---|
| Staging area Staging options Uncommitted files in the local branch |
第 345 页 / 共 465 页
9.2 Git Basics
Push, or Stash the changes, as shown in Figure 9.15. If you’ve already pushed a change,
and you need to amend the new change to the previous push, then you must check
the Amend checkbox before clicking the Push button.
Figure 9.15 Staging Area Amend, Commit, Commit and Push, Push, and Stash Options
Now that we’ve covered the concepts related to the Git pane, let’s get back to the step
where we linked the local branch with the remote branch in the GitHub. After linking
with the remote branch, click on the Pull button 1, as shown in Figure 9.16, to sync
the remote branch with the local branch (the remote branch didn’t have any code in
it other than a Readme file, so it shouldn’t create any conflicts). After this, it’s time to
submit all the code in the local branch for the project back to the remote branch and
make the first commit. Enter your commit message 2, as shown in Figure 9.16, and
then click on the Commit and Push button (see Figure 9.16, 3). This will submit all the
code from the local branch to the remote branch.
Figure 9.16 Making the Initial Commit to the Master Branch
345
第 346 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
When you click Commit and Push, notice that the SAP Web IDE is giving you two
options for the branch to commit (see Figure 9.17). The origin/master option points
toward the original remote master branch of your local branch, and the Remote
Branch option gives you a list of available remote branches to choose from. For this
scenario, select origin/master from the list, and SAP Web IDE will create this branch
in the remote repository.
Figure 9.17 SAP Web IDE Creating a New Remote Repository for the Initial Commit
A popup window will appear to enter your GitHub credentials to make the commit.
Enter the details of your GitHub account, and click on the OK button (see Figure 9.18).
Figure 9.18 Entering the GitHub Account Credentials to Commit the Code
346
第 347 页 / 共 465 页
9.2 Git Basics
Now, if you log in to your GitHub account, you should be able to see all the code com-
mitted from the SAP Web IDE in your repository (see Figure 9.19).
Figure 9.19 Committed Code Now Visible in GitHub
9.2.5 Cloning the Project into SAP Web IDE
To discuss the Fetch, Merge, and Pull options from the perspective of another devel-
oper who is working on the same project in SAP Web IDE, let’s clone the newly created
remote branch from GitHub and clone it into the SAP Web IDE. To replicate a scenario
of two developers working on the same project, this additional cloned project into
the SAP Web IDE will act as the second developer. We’ll then submit code from the
original project (in which we initialized a local repository and then later linked with
the GitHub remote repository) and retrieve/merge codes into the cloned project in
the same SAP Web IDE to simulate the scenario.
To clone projects from Git, go to File (cid:2) Git (cid:2) Clone Repository, as shown in Figure 9.20.
347
第 348 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
Figure 9.20 Cloning the Git Repository in SAP Web IDE
In the popup window, enter the GitHub repository URL (it’s the same URL we copied
earlier in this chapter when creating the initial repository in GitHub), and click the
Clone button (see Figure 9.21).
Figure 9.21 Entering the GitHub Repository URL to Clone the Project
Now, let’s create a new local branch within the SAP Web IDE. Click on the + icon, as
shown in the Figure 9.22.
Figure 9.22 Adding a New Local Branch
348
第 349 页 / 共 465 页
9.2 Git Basics
Let’s name the new branch “ALPFeatureBranch” and the Source Branch “master” (see
Figure 9.23) because we need a copy of the master branch to the new local branch.
Click OK.
Figure 9.23 Creating the New Local Branch
Now the new local branch is created, and you can see that the new branch is selected
in the Git pane, as shown in Figure 9.24.
Figure 9.24 The New Local Branch Added to the Cloned Project in SAP Web IDE
Now let’s open the project that has only one local branch (master branch) and push
some changes to the remote branch. For example, one of the developers made a few
changes in the i18n file and committed the changes to the master branch. In Figure
9.25, you can see the files that have been changed in the staging area; the developer
can select or deselect the files accordingly and then commit the changes. You can see
that the developer selected the project.json and i18n.properties files to be staged. The
extended_runnable_file.html file was unselected and hence won’t be pushed to the
remote branch. When you commit the changes to the remote repository, it will be
updated in the master branch to which the SAP Web IDE had made the initial commit.
349
第 350 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
Files selected to
be committed
from staging area
Files excluded from staging
area for commit
Figure 9.25 Staging Area in the SAP Web IDE for the Git Pane
9.2.6 Getting Code from the Remote Branch (Fetch, Merge, Pull)
Now let’s fetch the new changes from the remote branch that have been pushed from
the other project to the new local branch and then merge the changes from the remote
branch to the new local branch. In this case, however, the second developer was also
editing the same i18n.properties file. But first the developer needs to check whether
any new changes were pushed to the remote branch already by another team member
or not, so the developer clicks on the Fetch icon, as shown in Figure 9.26.
Figure 9.26 Initiating a Fetch to Look for Changes in the Remote Branch
350
第 351 页 / 共 465 页
9.2 Git Basics
The Fetch action detected changes in the remote branch and lists the changes in a
popup window, as shown in the Figure 9.27.
Figure 9.27 Fetch Action Detecting Changes from the Remote Branch
Now, the developer attempts a Merge action by clicking on the Merge button, as
shown in Figure 9.28. They try to merge the code from the master branch to the new
local feature branch.
Figure 9.28 Merging the New Local Branch with the Remote Branch
But the Merge request fails, as shown in Figure 9.29, because there were changes in the
same file (if there were no changes on the same file in this new local branch, then a
351
第 352 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
Merge/Rebase request would have worked just fine). Now the developer must either
discard the changes and then attempt a Merge or use the Stash option. In this case,
because it was a very minor change, it wouldn’t be an issue. But let’s assume the
changes were too big, and the developer just didn’t want to back up the codes manu-
ally into a notepad and then attempt a Merge request after discarding the changes in
the local repository. This is where the Stash feature in Git comes in handy for devel-
opers.
Figure 9.29 Merge Request Failure Due to File Conflicts
Toward the bottom of the staging area, you can see that the Stash button is now
active. Click on the Stash button as shown in Figure 9.30. As we explained earlier in
the chapter, Stash is like a temporary storage for your uncommitted codes that gives
you the option to retrieve it at a later point so that you can switch between branches
without losing those changes.
Figure 9.30 Stash Option in the Git Pane
In the next window, you must give a description for your stashed code so that you
can identify it later while trying to retrieve it. Enter the required Description (in this
352
第 353 页 / 共 465 页
9.2 Git Basics
case, we gave the description as “i18n File Changes backup”), and click on the Stash
button, as shown in Figure 9.31.
Figure 9.31 Naming the New Stash File
After the local changes have been stashed, the developer can initiate the Merge
action 1, and this time, it will be successful without any conflicts, and the new
changes from the master branch will be visible in the new local branch as well (see
Figure 9.32). Now it’s time to retrieve the stashed codes back into the project. Click on
the Apply Stash button 2 in the Git pane as shown in Figure 9.32.
Codes have been merged from the master branch with
the new local branch after clicking on the Merge button
Figure 9.32 Merging and Applying Stash in the Git Pane
A new window will appear with the list of saved stash files. Select the Stash file, click
on the second radio button (the developer can choose whether to keep the stashed
files for future use or discard them), and click on Continue, as shown in Figure 9.33.
353
第 354 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
Figure 9.33 Selecting the Saved Stash from the Popup Window
Now the previously uncommitted codes will reappear in the files as shown in Figure
9.34. The developer can commit these changes back to the master branch after the
development in the local branch is completed.
Figure 9.34 The Stashed Codes Now Restored to the Local Branch
Let’s assume these new changes in the local branch have been completed by the sec-
ond developer, and he has committed it back to the master branch. The other team
members can now get the latest code from the central repository by clicking on the
354
第 355 页 / 共 465 页
9.2 Git Basics
Pull button from the Git pane, and all the local branches will be synchronized with the
remote branch (see Figure 9.35).
Figure 9.35 Initiating a Pull Request to Retrieve the Latest Code from the Remote Master
Branch
9.2.7 Working with Branches
When your development project should deliver multiple versions of the product
over time, it makes sense to divide the remote repositories into different iterations
based on the features or versions of the product. But you’ll always have a master/
infinity branch which will contain the latest code. Different version branches of the
software are created periodically form this mast branch. Figure 9.36 shows a scenario
with multiple remote and local branches. Each remote branch may have n number of
local branches based on the project requirements. This multiple remote branch
approach makes it easier to divide what each version of a product is supposed to
deliver, and developers can continue to provide support to older versions to address
bugs within the product, issuing patches, and so on. Developers could even choose to
downport a certain feature to the older version of the product if necessary.
For this chapter, we’ll create two additional remote branches: one branch using
GitHub and one remote branch directly from the SAP Web IDE. Then we’ll create the
local branches in the SAP Web IDE from those remote branches.
355
第 356 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
GitHub Repository
m
I
nitial Co m
mit
Critical B ug
Fix
Merge
F e
C
a
o
t
m ur
m
e
i
B
t
r
f
a
ro
nc h
Ongoing
Master Remote Branch Developments
Commit History Time Line
Bug
Fix
Release Version 1.0 Remote
Support Phase
Branch Commit History
Time Line
Bug
Fix
Release Version 2.0
Support Phase
Remote Branch Commit
History Time Line
Merge Commit
Master Local Branch
Local Feature Branch
Created from Master
Branch
Release Version 1.0 Local
Branch
Release Version 2.0 Local
Branch
SAP Web IDE Local Branches
Figure 9.36 Working with Multiple Remote and Local Branches
First, let’s create a new remote branch called ReleaseVersion1.0 in the GitHub. Open
the repository for the project, click on the Branch:master button shown in Figure 9.37
1, and type in the new branch name 2. Then click on the Create branch: ReleaseVer-
sion1.0 option 3 in the bottom-left corner of the screen.
356
| Merge Commit Master Local Branch Local Feature Branch Created from Master Branch Release Version 1.0 Local Branch Release Version 2.0 Local Branch SAP Web IDE Local Branches | Merge Commit | ||
第 357 页 / 共 465 页
9.2 Git Basics
Figure 9.37 Creating a New Remote Branch in GitHub
Now let’s create a new remote branch named ReleaseVersion2.0 using SAP Web IDE.
Right-click on the project, and go to Git (cid:2) Create Remote Branch (Figure 9.38).
Figure 9.38 Creating a New Remote Branch from SAP Web IDE
In the new popup window, select the Source Branch as the remote branch origin/mas-
ter (see Figure 9.39). Give the Branch Name as “ReleaseVersion2.0” (this will make a
copy from the Master remote branch so that all the changes so far will be carried for-
ward to the new remote branch).
357
第 358 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
Figure 9.39 Creating a New Remote ReleaseVersion2.0 Branch
After the new remote branches have been created, you can start creating the local
branches within SAP Web IDE in the Git pane 1. Click on the + icon 2 next to the
Branch dropdown list, as shown in Figure 9.40. From the popup window, select the
Source Branch from which you want to create your local branch, and click on the OK
button 3.
Figure 9.40 Creating a New Local Branch from Remote ReleaseVersion2.0
358
第 359 页 / 共 465 页
9.2 Git Basics
Create all the local branches based on your project requirements. After all the
branches have been created, you can see them in the dropdown list field in the Git
pane in the SAP Web IDE, as shown in Figure 9.41.
Figure 9.41 Overview of All Branches in SAP Web IDE Git Pane
You can also view all the remote branches directly in the GitHub page (see Figure
9.42). With this approach, developers can easily work on different branches based on
the project release cycles or feature releases. This makes working with multiple devel-
opers on your team on the same project much easier.
Figure 9.42 Overview of All Remote Branches in GitHub
359
第 360 页 / 共 465 页
9 Version Control in SAP Web IDE Using Git
9.3 Summary
In this chapter, you learned about the Git repository and how to use GitHub as an
extension to create and manage repositories in Git. We covered creating local repos-
itories in SAP Web IDE and linking them with the remote Git repository. We went
through the basic GitHub options, including Pull, Fetch, Rebase, Merge, and Reset in
the Git pane of the SAP Web IDE. You also learned how to commit, push, and stage
codes in to the remote repositories from SAP Web IDE. We discussed how to create
multiple local branches and remote branches, as well as how to work with multiple
branches for development. In the next chapter, you’ll learn about automated testing
on the SAP S/4HANA platform.
360
第 361 页 / 共 465 页
Chapter 10
Automated Testing
Automated testing is key for ensuring software quality across soft-
ware releases and for catching bugs early and frequently. In this
chapter to will learn how to create automated tests for all layers of
your SAP S/4HANA applications from the SAP HANA database over
the ABAP business logic to the SAPUI5 frontend part.
Traditionally, software was mostly tested manually by testers following scripts
ensuring consistent testing for each release. The software was deployed to a testing
environment, and the testers did black-box style testing by clicking through the user
interface (UI) of the application checking whether anything is broken. It’s obvious
that this is very time consuming and tedious, and it quickly becomes unfeasible. The
only way to escape this negative spiral of manual repetitive testing is to automate the
tests as much as possible. If your software is accompanied by a comprehensive auto-
mated test suite, determining whether your software works or not is a matter of sec-
onds not hours or days. Consequently, test automation is the foundation for shorter
release cycles and faster customer feedback as automated tests are an integral part of
any build pipeline that automatically tests and, if successful, deploys the software to
a test or production environment. To achieve good coverage of all functional aspects
and parts of the software, an extensive test suite usually consists of several layers, as
depicted in the test automation pyramid shown in Figure 10.1.
The unit tests written using test-driven development (TDD) make up the foundation
layer of the pyramid. These tests specify the software at the lowest possible level, usu-
ally on the public method or function level, and are written before the production
code. They play a decisive role in increasing code quality by enforcing testability,
decoupling, and modularity. When developing applications for the SAP S/4HANA plat-
form, you can write unit tests in the backend by using ABAP Unit, which is integrated
into the ABAP runtime, and by using QUnit, which is included in the SAPUI5 SDK, in
the frontend. The rule of thumb is one unit test class/object per ABAP or JavaScript
class/object and several test methods/functions for one production method/function
covering all code paths (happy path and edge cases). As you can see from the width of
361
第 362 页 / 共 465 页
10 Automated Testing
this layer in the pyramid, unit tests outnumber all other tests in the pyramid. They
should cover your code as close to 100% as reasonable. Because the SAP S/4HANA plat-
form is database-centric, and operations on data are supposed to be pushed down to
SAP HANA either via Core Data Services (CDS) views or OpenSQL, SAP provides CDS
Test Double Frameworks that allow you to test their contained logic and calculations
isolated from underlying views and tables using ABAP Unit as a test runner. To isolate
methods under test containing ABAP business logic from their dependencies or
depended-on components (DOC), you can use the ABAP Test Double Framework. The
counterpart in the frontend, included with the SAPUI5 SDK, is Sinon.JS.
Test costs
and runtime
End-to-End
Tests (E2E)
Selenium,
WebDriver,
Nightwatch.js
Integration Tests
Frontend: OPA5, Mockserver
Backend: ABAP Unit, ABAP Test Double
Framework, CDS Test Double Framework,
OpenSQL Test Double Framework
Unit Tests
Frontend: QUnit, Sinon.JS
Backend: ABAP Unit, ABAP Test Double Framework, CDS Test
Double Framework, OpenSQL Test Double Framework
Effort and test coverage
Figure 10.1 Test Pyramid Layers and Respective Testing Tools for SAP S/4HANA Applications
362
第 363 页 / 共 465 页
10.1 Backend Test Automation
In integration tests, several previously unit-tested individual software modules (e.g.,
several classes) are combined and tested together. In the SAP S/4HANA backend, you
can basically use the same technologies as for unit tests to write integration tests.
You can isolate them from additional unwanted dependencies using one or more of
the provided test double frameworks and only test the integrations relevant for your
particular test case. In the frontend, integration tests can be written using the One-
Page Acceptance (OPA5) framework included with the SAPUI5 SDK. To isolate the
tests from the backend, a mock server with mock data can be used. It handles OData
read requests locally by returning predefined mock data and is also capable of dealing
with write accesses (POST, PUT, MERGE) to OData entities by persisting them in-memory
for the runtime of the test.
In end-to-end (E2E) tests, you want to test the application how an end user would test
the app via its UI in an automated way. E2E tests give you the most confidence that
the application is working correctly because they cover the frontend and the backend
part of the application as well as their interaction and integration. At the same time,
such tests are usually more fragile and slow compared to isolated unit or integration
tests. In the SAP S/4HANA environment, executing such tests requires a dedicated
test system with existing master data and stable Customizing; otherwise, these tests
might fail often and lead to a lot of false positives. Maintaining a large set of E2E tests
can quickly become a full-time job if there is no dedicated and stable test system.
Therefore, E2E tests usually cover only the standard process of an application without
testing all edge cases. Edge cases are supposed to be covered by lower level tests.
In the rest of this chapter, you’ll learn how to use the different testing frameworks in
the frontend and backend to cover all layers of the testing pyramid when developing
applications on the SAP S/4HANA platform.
10.1 Backend Test Automation
We’ll first look at how to write unit tests for the main technologies in the backend of
an SAP S/4HANA application: ABAP and CDS. We’ll start with introducing ABAP Unit
and subsequently develop an ABAP unit test for a CDS calculation. During the devel-
opment of the unit tests, we’ll also introduce dependency injection techniques to iso-
late the code under test (CUT) from its depended-on components (DOC), primarily
the object factory class pattern, and the ABAP Test Double Framework for creating
test doubles. In the next section, we’ll (re)introduce the CDS Test Double framework
in depth. After this, you should be able to write unit tests for the backend part of your
SAP S/4HANA applications.
363
第 364 页 / 共 465 页
10 Automated Testing
10.1.1 Unit Testing (ABAP Unit)
ABAP Unit is SAP’s unit testing framework for ABAP. Unit tests for ABAP classes are typ-
ically implemented in a local test class of a global class to be tested with the addition of
FOR TESTING of the CLASS statement. The test class will contain several test methods
that also have the addition FOR TESTING added to their method definitions. In addition
to the test methods, the class can contain test fixture methods that are called at pre-
defined times by the ABAP Unit Runner; for instance, the static class_setup() and
class_teardown() methods will be called before and after the test methods are run.
They can be used for general setup and cleanup activities relevant for the whole test
suite. The setup() and teardown() methods, if present, will be called before and after
each test method execution. The sequence in which the test actual methods are exe-
cuted is undefined. The test fixture methods can therefore be used to create, re-create,
and clean up a defined state before and after a test method is executed. Additionally, a
new instance of the test class is created for each test method, which prevents unwanted
side effects due to states conserved between different test method runs. Figure 10.2
summarizes the sequence in which the ABAP Unit Runner invokes the methods of the
local test class in an Unified Modeling Language (UML) sequence diagram. To check the
result of a method under test, SAP provides the CL_ABAP_UNIT_ASSERT class, which con-
tains different static methods for comparing expected and actual values.
ABAP_UNIT : Local Test
Testrunner Class
run unit tests
class_setup()
Instance
: Local Test
create object Class
setup()
For each
method for
call test method()
testing
teardown()
class_teardown()
rollback work
Figure 10.2 UML Sequence Diagram for an ABAP Unit Test Run
364
| Instance : Local Test Class |
第 365 页 / 共 465 页
10.1 Backend Test Automation
Create an ABAP Unit Test in ABAP Development Tools
You can create a local test class for a global ABAP class opened in the editor of the
ABAP development tools in Eclipse by selecting the Test Classes tab, entering “test-
Class” into the editor, and pressing (Ctrl)+(Space) and (Enter). This will insert the
testClass code template into the editor, which consists of a local skeleton unit test
class (Figure 10.3).
Figure 10.3 Creating a Unit Test Class Skeleton Using the Provided ABAP Development Tools
testClass Code Template
You can run unit tests using the shortcut (Ctrl)+(Shift)+(F10) or (Ctrl)+(Shift)+
(F11) (including coverage).
Add a Virtual Element to a Core Data Services View
Let’s say we want to add an additional Vendor Rating field to our purchase order item
OData and CDS entity (Z_C_PurchaseDocumentItemLrp) indicating how well a vendor of
goods is rated ranging from zero to five starts (see Figure 10.4). However, this infor-
mation isn’t present on the database or at least not in a format that we can easily con-
sume it via CDS. Fortunately, there is already an ABAP service class (zcl_vendor_
service) that provides this information conveniently via a get_vendor_rating()
method. This is a common use case for a virtual element in a CDS view populated by
an ABAP exit. It isn’t possible yet to push the logic down to SAP HANA using CDS
views, and the business logic is simply too complex to rewrite it in a reasonable time
frame. The only thing you can do is to read the field values using an ABAP code exit.
Keep in mind that this might negatively impact the performance of the application as
not all data processing is pushed down into SAP HANA.
365
第 366 页 / 共 465 页
10 Automated Testing
Figure 10.4 New in ABAP: Calculated Vendor Rating Column
Listing 10.1 shows how to add the virtual VendorRating field to the field list of the Z_C_
PurchaseDocumentItemLrp CDS view. The field is marked as read only (@Object-
Model.readOnly: true) and as virtual because it doesn’t exist on the database
(@ObjectModel.virtualElement: true). The values of the virtual field or element are
calculated by the ZCL_VENDOR_RATING_CALC_EXIT ABAP class.
…
@EndUserText.label: 'Vendor Rating'
@ObjectModel.readOnly: true
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VENDOR_RATING_CALC_EXIT'
0 as VendorRating,
…
Listing 10.1 Add the Virtual VendorRating Field to the Z_C_PurchaseDocumentItemLrp CDS View
Create an ABAP Code Exit for a Virtual Core Data Services Element
The zcl_vendor_rating_calc_exit must implement the interface if_sadl_exit_calc_
element_read, which has two methods (get_calculation_info() and calculate()), as
shown in Figure 10.5.
The get_calculation_info() method is called before data is selected from the data-
base via the generic Service Adaptation Definition Language (SADL) CDS entity SELECT
(in our case, on Z_C_PurchaseDocumentItemLrp). The calculate()method is called after
the original data is read from the database. Its purpose is to calculate the virtual ele-
ments based on the original data. Figure 10.6 shows an oversimplification of when
the methods are invoked by the SADL engine using a UML sequence diagram.
366
第 367 页 / 共 465 页
10.1 Backend Test Automation
Figure 10.5 ABAP Calculation Exit for Vendor Ratings zcl_vendor_rating_calc_exit,
Which Must Implement the Interface if_sadl_exit_calc_element_read
ABAP Code
SADL CDS Entity
Exit
GET Entity
get_calculation_info()
get_requested_orig_elements
SELECT original elements via CDS view
Original data
calculate()
ct_calculated_data
Figure 10.6 SADL Performs the Generic Database Select and Invokes the get_calculation_
info() and calculate() Methods of the ABAP Exit in This Sequence
367
第 368 页 / 共 465 页
10 Automated Testing
Implement the get_calculation_info() Method using Test-Driven Development
In the get_calculation_info() method, we must provide all fields that are required to
later calculate the virtual element values in the calculate() method. In our case, we
need the VENDOR field to be selected from the database if the VendorRating field is
requested because we need to pass the VENDOR as a parameter to the get_vendor_rat-
ing() method of the zcl_vendor_service class. With this specification, we can write
our first vendor_rating_selected test, shown in Figure 10.7. We create an instance of
the calculation exit and call its get_calculation_info() method passing the VENDOR-
RATING field, as a requested calculated field, and the entity name of our CDS views as
parameters.
Figure 10.7 Local Test Class with the First Test Method for Our Vendor Rating ABAP Calcula-
tion Exit
The test will fail because we haven’t yet implemented anything in our CUT according
to the TDD practice. We can fix the test by simply appending the VENDOR field to the
et_requested_orig_elements table inside the get_calculation_info() method of the
368
第 369 页 / 共 465 页
10.1 Backend Test Automation
zcl_vendor_rating_calc_exit class. However, what happens when the VENDORRATING
field isn’t contained in the it_requested_calc_elements table? In this case, we
shouldn’t append the VENDOR field to the requested original elements table (et_re-
quested_orig_elements) because we’re not supposed to read anything not requested
for performance reasons. We can write a test for this scenario as shown in Figure 10.8.
Figure 10.8 Making Sure the VENDOR Field Isn’t Added to the Requested Original Elements
Table If the VENDORRATING Field Isn’t Requested
We can fix the test by checking whether the VENDORRATING field is requested or con-
tained in the importing table it_requested_calc_elements. If this isn’t the case, we
simply don’t append it to the et_requested_orig_elements exporting table (see Figure
10.10). Additionally, we want to make sure that our calculation exit can’t be called for
an entity other than Z_C_PurchaseDocumentItemLrp. The corresponding test is shown
in Figure 10.9. If the entity doesn’t equal Z_C_PurchaseDocumentItemLrp, we expect an
zcx_unkown_entity exception inheriting from cx_sadl_exit. The static cl_abap_unit_
assert=>fail() method call is reached only if the exception isn’t thrown. The actual
final implementation of the get_calculation_info() method is shown in Figure 10.10.
Figure 10.9 If the Passed Entity Isn’t Equal to Z_C_PurchaseDocumentItemLrp, Expect an
zcx_unknown_entity Exception
369
第 370 页 / 共 465 页
10 Automated Testing
Figure 10.10 Final Implementation of the get_calculation_info method() for the VENDOR-
RATING Field
Implement the calculate() Method Using TDD and an Object Factory Class
In the next step, we want to implement the calculate() method of the exit in a TDD
fashion. Figure 10.11 shows our test implementation. We’re calling the calculate()
method of the ABAP exit with an original data table containing VendorA. Additionally,
we request the VENDORRATING element to be calculated. As a result, we expect the orig-
inal data to be extended with a vendor rating of 5 (stars).
Figure 10.11 Test for the calculate() Method of the ABAP Calculation Exit
Of course, the test will initially fail as we haven’t implemented anything yet inside
the calculate() method of our ABAP exit class zcl_vendor_rating_calc_exit. In con-
trast to the get_calculation_info() method, the calculate() method has a depen-
dency to another ABAP class as we must read the vendor rating via an already
existing zcl_vendor_service ABAP service class (see Figure 10.12). The class has a pub-
lic method get_vendor_rating(), which returns the rating for a certain vendor that
must be passed as a parameter.
370
第 371 页 / 共 465 页
10.1 Backend Test Automation
<<interface>>
if_sadl_exit_calc_element_read
+ get_calculation_info()
+ calculate()
ztd_vendor_service
+ get_vendor_rating(vendor)
zcl_vendor_rating_calc_exit
zcl_vendor_service
+ get_calculation_info()
+ get_vendor_rating(vendor)
+ calculate()
Figure 10.12 Ratings for a Vendor Must be Read via the zcl_vendor_service Class
Because we don’t want to test the get_vendor_rating() dependency inside our unit
test (we assume that this functionality already has its own unit test and is working
properly), we must cut and replace this dependency at test runtime with a test double
(ztd_vendor_service), which is a test-specific equivalent returning fixed predefined
ratings. Using a test double instead of the actual dependency allows us to focus on
testing the code we’re going to implement and prevents our tests from failing when
dependencies fail. So, if our test fails, it’s clear that it’s due to our code, and we can
immediately localize the problem without having to analyze the code of dependen-
cies. For being notified of bugs and regressions in the get_vendor_rating() method
when interacting with the calculate() method, we might consider writing an inte-
gration test.
To make the dependency replaceable in a test, we can’t simply instantiate the vendor
service inside the calculate method. We must make this dependency injectable into
the zcl_vendor_rating_calc_exit class using one of the dependency injection tech-
niques listed in Table 10.1.
Technique Description
Constructor injection The dependencies are provided and set through the construc-
tor of the class.
Setter injection The class provides a setter method for each dependency.
Table 10.1 Dependency Injection Techniques
371
| <<interface>> if_sadl_exit_calc_element_read |
|---|
| + get_calculation_info() + calculate() |
| ztd_vendor_service |
|---|
| + get_vendor_rating(vendor) |
| zcl_vendor_rating_calc_exit |
|---|
| + get_calculation_info() + calculate() |
| zcl_vendor_service |
|---|
| + get_vendor_rating(vendor) |
| Technique | Description |
|---|---|
| Constructor injection | The dependencies are provided and set through the construc- tor of the class. |
| Setter injection | The class provides a setter method for each dependency. |