ABAP Development for SAP S4HANA (SAP PRESS) (第12页)

第 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.
返回ABAP参考资料列表