2019 June Release

Testing your Cloud AppPermanent link for this heading

We all know that testing is important. Today’s test-driven development methodologies even require us to write our tests as we go rather than at the end of the process.

Still, for most of us developer folks coding is much more fun, so we usually tend to focus on the part that’s more fun and procrastinate when it comes to testing.

Well, we’ve got bad news for you: If you want to see your Cloud App going live anytime soon you have to embrace the idea of writing tests whenever you add or change something in your code.

Testing takes time. Don’t forget to allocate a fair amount of time to designing, writing and updating robust tests also taking into account the corner cases. It’s not in vain though, because in Fabasoft Cloud quality pays dividends.

Why are we so strict when it comes to testing?

Because creating and continuously running a battery of automated tests is the only way you can keep huge amounts of existing code from breaking as you integrate new code.

Every Cloud App contributes new code into Fabasoft Cloud, and the only way to maintain our standard of exceptional code quality is to enforce to our processes that uphold quality above all.

So what does this mean for you as a Cloud App developer?

Basically, it means that you have to produce the following deliverables in addition to your actual Cloud App:

  • Unit tests for all of your use cases that are not implemented as virtual applications
  • Fabasoft app.test tests for all of your Fabasoft app.ducx expression code that cannot be covered by unit tests
  • A combined code coverage target ratio of 100 %

Creating and running unit testsPermanent link for this heading

Unit tests are an integral and essential part of every modern software development methodology and provide a quick way to boost your code coverage. In this chapter you will learn how easy it is to define and execute unit tests for your Cloud App.

Creating a unit testPermanent link for this heading

Unit tests are part of your Fabasoft app.ducx project and must be defined in a Fabasoft app.ducx unit test file.

The skeleton project generated for your Cloud App already contains a sample unit test in a file named unittest.ducx-ut, so we’ll just add our unit tests to this file.

For each unit test, you have to define an instance of FSCDUCXUNIT@1.1001:UnitTest using the test keyword as illustrated by the example presented later on.

For the sake of brevity, we will only include a single unit test in this book. However, you can obtain the full source code for our Cloud App (including all the unit tests) from the public Subversion repository (see chapter “Retrieving code samples from the public Subversion repository”).

As a rule of thumb, you should define a unit test for each and every use case in your project that is not implemented as a virtual application. Virtual applications and all the other stuff that needs a GUI must be covered by Fabasoft app.test tests.

Generally, it’s a good idea to have a separate unit test per use case, but you may also combine logically related use cases into a single unit test. This is exactly what we’ll be doing in our example, where we will cover the RecordTrip use case and the InitTrip use case with the same unit test.

A unit test is comprised of three Fabasoft app.ducx expressions:

  • The init expression allows you to define a setup expression for creating and initializing the test containers for your unit test.
  • In the expression block, cover all the possible test cases for the use case to be tested by your unit test. This is the “main body” of the unit test.
  • The cleanup expression allows you to define a cleanup expression for deleting the test containers used by your unit test.

A unit test is based on a test scenario that allows you to prepare certain test configurations that can be reused among your set of unit tests. Using the scenario keyword, you can define your own test scenarios.

The skeleton project already contains a blank test scenario derived from the FSCFOLIOCLOUDUT@1.1001:SCPrepareAppOrgEng test scenario, which takes care of creating a test organization, a number of test users, an app configuration and an instance of your app room so you don’t have to worry about setting up the basic infrastructure for your unit tests.

Note: Derive your test scenario from FSCFOLIOCLOUDUT@1.1001:SCPrepareAppOrgGer in order to get German language test users.

Keep the following important things in mind when writing a unit test:

  • By default, unit tests are executed in the user context of the user launching the unit test. Use the coouser.SwitchToUser() call to login as a different user and execute commands in context of a regular test user. While certain tasks need to be carried out in the administrator context you are advised to do the main testing work in context of a regular user.
  • The FSCDUCXUNIT@1.1001:CreateTestGroup and FSCDUCXUNIT@1.1001:CreateTestUser actions allow you to create test organizations and test users in case you need additional users or want to implement complex test configurations. However, in most cases you should be just fine with the test organization and the test users provided by the FSCFOLIOCLOUDUT@1.1001:SCPrepareAppOrgEng base scenario.
  • Add assertions to your expression code using the %%ASSERT directive to check if your test conditions are fulfilled. If at runtime a condition is not met, the assertion yields false and the unit test fails.
  • Make sure that every branch of your use case implementation is covered, also the error handlers. You can use try-catch blocks to raise errors and test if they are handled correctly.
  • Don’t forget to cover the corner cases and also try to anticipate obscure scenarios.
  • Clean up after yourself and delete all of the test objects created by your unit test. Test objects created by base scenarios (such as FSCFOLIOCLOUDUT@1.1001:SCPrepareAppOrgEng) are deleted automatically and children of an app room are deleted with the app room.

The following example shows how to define a unit test.

Example

unittest.ducx-ut

unittests FSCLOGBOOK@111.100
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;
  import COOATTREDIT@1.1;
  import FSCDUCXUNIT@1.1001;
  import FSCFOLIOCLOUDUT@1.1001;

  /*
   * Use
the English language Cloud base scenario, which creates the following
   * test objects
(that will also be cleaned up automatically at the end):
   * User admin: administrator user

   * User orgowner: owner of the test organization

   * User orgadmin: administrator of the test organization

   * User appadmin: administrator of your app configuration

   * Group org: test organization

   * ExtOrganization extorg: external test organization

   *   (mainly for testing use cases involving external partners)

   * User member1: test user 1 (member of org)

   * User member2: test user 2 (member of org)

   * User member3: test user 3 (member of org)

   * User member4: test user 4 (member of org)

   * User extmember1: external member 1 of extorg

   * User extmember2: external member 2 of extorg

   * User extmember3: external member 3 of extorg

   * User extmember4: external member 4 of extorg

   * AppConfigurationRoom config: instance of your app configuration

   * AppRoom[] approoms: instance of your app room

   *   (
if your Cloud App defines multiple app room classes you’ll get
   *   one instance per app room class
)
   */
  scenario SCAppSuperTest : SCPrepareAppOrgEng {
    compapps = AppFSCLOGBOOK;
    init = expression {
      // No specific initializations necessary
    }
    cleanup = expression {
      // No cleanup necessary
    }
  }

  test UnitTestRecordTrip using SCEmpty {
    init = expression {
      // Create and initialize test data
      coouser.SwitchToUser(member1);

      SelectionContext selctx = {
        selview : #acapprooms,
        selcontainer : config
      };
      #TV.TV_SELECTIONCONTEXT = selctx;
      #TV.TV_SELECTIONCONTAINER = selctx.selcontainer;
      Logbook logbook = approoms[0];
      Logbook.ObjectLock(true, true);
      logbook.objname = "My Logbook";
      logbook.logvehicleid = "AG76282";
      cootx.Commit();

      selctx = {
        selview : #logtriplogs,
        selcontainer : logbook
      };
      #TV.TV_SELECTIONCONTEXT = selctx;
      #TV.TV_SELECTIONCONTAINER = selctx.selcontainer;
      TripLog triplog = #TripLog.ObjectCreate();
      triplog.ShareObject(, , #logtriplogs, logbook);
      cootx.Commit();
      %%ASSERT(triplog in logbook.logtriplogs);
    }

    expression {
      // Test the "RecordTrip" and "InitTrip" use cases
      TripLog triplog;
      Trip trip = null;

      try {
        triplog.RecordTrip(trip);
        %%FAIL;
      }

      catch (#ErrIncompleteTripInfo) {
      }

      triplog.InitTrip();

      %%ASSERT(triplog.trlnewtrip != null);
      %%ASSERT(triplog.trlnewtrip.trpstartmileage == null);
      %%ASSERT(triplog.trlnewtrip.trpdriver == coouser);
      %%ASSERT(triplog.trlnewtrip.trptype == #TermBusiness);

      triplog.ObjectLock(true, true);
      triplog.trlnewtrip.trpdepartureat = coonow - 9*60*60;
      triplog.trlnewtrip.trparrivalat = coonow - 6*60*60;
      triplog.trlnewtrip.trpdepartureplace = "New Haven, CT";
      triplog.trlnewtrip.trpdestinationplace = "Boston, MA";
      triplog.trlnewtrip.trpstartmileage = 10000;
      triplog.trlnewtrip.trpendmileage = 10150;
      triplog.trlnewtrip.trppurpose = "Customer Visit";

      triplog.RecordTrip(triplog.trlnewtrip);
      cootx.Commit();

      %%ASSERT(count(triplog.trltrips) == 1);
      %%ASSERT(triplog.trltrips[0].trpmileage == 150);
      %%ASSERT(triplog.trltrips[0].trpduration == 3*60*60);
      %%ASSERT(triplog.trltrips[0].trpdriver == null);
      %%ASSERT(triplog.trltrips[0].trpdrivername == coouser.GetName());
      %%ASSERT(triplog.trlnewtrip == null);

      triplog.InitTrip();

      %%ASSERT(triplog.trlnewtrip != null);
      %%ASSERT(triplog.trlnewtrip.trpstartmileage == 10150);
      %%ASSERT(triplog.trlnewtrip.trpdriver == coouser);
      %%ASSERT(triplog.trlnewtrip.trptype == #TermBusiness);

      triplog.ObjectLock(true, true);
      triplog.trlnewtrip.trpdepartureat = coonow - 7*60*60;
      triplog.trlnewtrip.trparrivalat = coonow - 5*60*60;
      triplog.trlnewtrip.trpdepartureplace = "Boston, MA";
      triplog.trlnewtrip.trpdestinationplace = "Salem, MA";
      triplog.trlnewtrip.trpendmileage = 10170;
      triplog.trlnewtrip.trppurpose = "Customer Visit";

      try {
        triplog.RecordTrip(triplog.trlnewtrip);
        %%FAIL;
      }
      catch (#ErrDepartureBeforeLastArrival) {
      }

      triplog.trlnewtrip.trpdepartureat = coonow - 4*60*60;
      triplog.trlnewtrip.trparrivalat = coonow - 5*60*60;

      try {
        triplog.RecordTrip(triplog.trlnewtrip);
        %%FAIL;
      }
      catch (#ErrArrivalBeforeDeparture) {
      }

      triplog.trlnewtrip.trpdepartureat = coonow - 4*60*60;
      triplog.trlnewtrip.trparrivalat = coonow - 3*60*60;
      triplog.trlnewtrip.trpstartmileage = 9999;
      triplog.trlnewtrip.trpendmileage = 10170;

      try {
        triplog.RecordTrip(triplog.trlnewtrip);
        %%FAIL;
      }
      catch (#ErrStartMileageLastEndMileage) {
      }

      triplog.trlnewtrip.trpstartmileage = 10175;
      triplog.trlnewtrip.trpendmileage = 10170;

      try {
        triplog.RecordTrip(triplog.trlnewtrip);
        %%FAIL;
      }
      catch (#ErrStartMileageEndMileage) {
      }

      triplog.trlnewtrip.trpstartmileage = 10150;
      triplog.trlnewtrip.trpendmileage = 10170;

      triplog.RecordTrip(triplog.trlnewtrip);
      cootx.Commit();

      %%ASSERT(count(triplog.trltrips) == 2);
      %%ASSERT(triplog.trlnewtrip == null);
    }

    cleanup = expression {
      // Nothing to clean up as all the created test objects were children of
      
// the logbook app room
    }
  }
}

Running a unit testPermanent link for this heading

Save and upload your changes into your Cloud App VDE (see chapter “Uploading your Cloud App into the Cloud Sandbox”) and point your browser to the Cloud Sandbox. Then log in using the “developer” account.

From within an administration tool, issue a search for the instance of object class “Unit Test” with the reference UnitTestRecordTrip and share it into the administration tool by selecting it in the list of search results and clicking “Next”.

Select “Run Test” from the context menu of the unit test to execute it. The dialog box shows the result of the execution.

Refer to [Faba19a] for further information on how to define and run unit tests.

Figure 45: Executing a unit test

Creating and running a unit test groupPermanent link for this heading

If you have multiple unit tests for your Cloud App, you can combine them into a unit test group. This allows you to select “Run Test” from the context menu of the unit test group to execute the whole battery of unit tests that are part of the group.

The following example shows how to define a unit test group.

Example

unittest.ducx-om

unittests FSCLOGBOOK@111.100
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;
  import FSCDUCXUNIT@1.1001;

  test UnitTest UnitTestInitTrip {
    …
  }

  test UnitTest UnitTestRecordTrip {
    …
  }

  testgroup UnitTestGroupLogbook {
    UnitTestInitTrip;
    UnitTestRecordTrip;
  }
}

Creating and running Fabasoft app.test testsPermanent link for this heading

Fabasoft app.test extends the testing possibilities of unit tests and enables you to conduct GUI testing. To test your Cloud App, Fabasoft app.test operates just like real human users would do when interacting with it.

While your unit tests ensure that your use cases can be executed with different input parameters and various settings, they don’t allow you to interact with the GUI components of your Cloud App. This is where Fabasoft app.test takes over as it complements your unit tests with automated test sequences imitating a human user working with your Cloud App.

In addition, Fabasoft app.test provides a range of customizable reports tailored to your needs.

Installing the Fabasoft app.test plug-inPermanent link for this heading

Before you can start creating your first test you need to install Fabasoft app.test.

Fabasoft app.test is packaged as a feature group consisting of multiple Eclipse features and plug-ins. For the sake of simplicity, this book sometimes refers to the entire collection of plug-ins making up Fabasoft app.test as “the Fabasoft app.test plug-in”.

You can install the Fabasoft app.test feature by opening the “Help” menu in Eclipse and clicking “Install New Software”. Click “Add”. In the following dialog, enter https://download.fabasoft.com/updates/update_apptest/ in the Location field and click “OK”.

Select the “Fabasoft app.test” feature group and click “Next”. Then click “Finish” to install Fabasoft app.test.

Refer to the Fabasoft app.test online help (available at https://help.apptest.fabasoft.com) and [Faba19b] for further information on Fabasoft app.test.

Importing the Fabasoft app.test projectPermanent link for this heading

In the next step, you have to import the skeleton project that was automatically created for your Cloud App from the Subversion repository.

Importing the Fabasoft app.test project using SubversivePermanent link for this heading

You can import the app.test project directly from Eclipse if you have “Subversive” installed (see chapter “Importing the Fabasoft app.ducx project from Subversion”).

In Eclipse, select “Import” from the “File” menu. In the “Import” dialog box that pops up, expand the “SVN” branch, select “Project from SVN” and click “Next”.

In the “Checkout from SVN” dialog box, paste the URL from the clipboard that is pointing to your Cloud App project in the Subversion repository. Then enter your Fabasoft Cloud credentials in the User and Password fields of the Authentication box and click “Browse” to log in to the Subversion repository.

In the “Select Resource” dialog box, expand the “trunk” branch and the “FSCLOGBOOK” branch underneath it, and select the “test” branch. Then click “OK” to return to the “Checkout from SVN” dialog box and click “Finish” to proceed with the import of your project from Subversion.

In the “Check Out As” dialog box that is opened next, confirm the suggested “Check out as project with the name specified” and click “Finish”.

The imported skeleton project for your Cloud App already contains the latest version of common test sequences and use cases. You are encouraged to integrate these reusable test sequences in your tests so that you don’t need to create sequences for common use cases (such as the login of a test user) by yourself. For further information about the common test sequences and use cases refer to [Faba19c].

Importing the Fabasoft app.test project using TortoiseSVNPermanent link for this heading

If you prefer to use TortoiseSVN to check out your Fabasoft app.test project, select “SVN Checkout” from the context menu of Microsoft Windows Explorer to open the dialog box.

In the URL of repository field enter the URL of your Cloud App in the Subversion repository and add the test folder to point it to the Fabasoft app.test project root. For our example, the full URL to the Fabasoft app.test project is:

https://cloud.fabasoft.com/svn/apps/FCB798DAF91D3911AB30860F534FADBA/trunk/FSCLOGBOOK/test

Note: Refer to the chapter “Creating the Cloud App project” for further information on how to retrieve the Subversion URL of your Cloud App.

After checking out the project, start Eclipse and select “File” > “Import” to bring up the dialog box. In the “Import” dialog box, select “Existing Fabasoft DUCXtest or Fabasoft app.test Projects into Workspace” from the “Fabasoft app.test” branch in the Select an import source field and click “Next”.

In the “Import Projects” dialog box, select the folder to where you checked out your Fabasoft app.test project in the Select root directory field and click “Finish” to finish the import.

Figure 46: Checking out the Fabasoft app.test project

Figure 47: Importing an existing Fabasoft app.test project

Figure 48: Selecting the Fabasoft app.test project to import

Creating a testPermanent link for this heading

Let’s create our first Fabasoft app.test test!

In a nutshell, the general structure of the Fabasoft app.test project for your Cloud App is as follows:

  • The project should contain a single test file invoking all of the sequences belonging to it.
  • Break down your test into as many logical sequences as you wish. Sequences should not contain any executions (e.g. “clicks”) though.
  • Each sequence of your test may contain multiple use cases that are responsible for carrying out the actual “work” (e.g. creating a logbook and filling out its properties).

For the sake of brevity, we will only focus on the absolute basics of creating a test. For further information refer to the Fabasoft app.test online help (available at https://help.apptest.fabasoft.com) and [Faba19b].

First of all, we need to create a test file. To create a test file, select “File” > “New” > “Test” and enter logbook.ducx-test in the File name field of the dialog box that is opened and click “Finish”.

Figure 49: Creating a new test

Figure 50: Editing the source code of a test

After creating the file, open the source code of the test by selecting the “Source” view of the logbook.ducx-test file, copy the code from the following example into the source code and save it.

The code is responsible for doing some initialization work before calling the createlogbook.ducx-seq test sequence, which we’re going to create in a subsequent step. Part of the initialization work is to acquire a license for your Cloud App for the test user.

Note: In the cloudapp parameter you have to provide the exact name of your Cloud App as it appears in the GUI (i.e. the name you defined in the mlnames.lang file).

Example

logbook.ducx-test

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Test name="logbook">
  <!-- ===================================================================== -->
  <!--  Global environment parameters                                        -->

  <!-- ===================================================================== -->

  <Sequence
name="Override Defaults">
    <Set
parameter="testlanguage"     value="LANG_ENGLISH" />
    <Set
parameter="reducedsettings"  value="false" />
  </Sequence>

  <Sequence
filename="PUBLIC/COMMON/PREREQ/Sequences/COMMON_PREREQ_ENVIRONMENT" />
  <Sequence
name="Global Parameters">
    
<!-- Define the name of your Cloud App in the "cloudapp" parameter -->
    <Set
parameter="cloudapp"         value="Driver's Logbook" />
    <Set
parameter="cloudappuser"     value="{~userid1_email~}" />
    <Set
parameter="tc"               value="Shared Logbooks {~testid~}" />
  </Sequence>

  <!-- ===================================================================== -->
  <!--  License Cloud App for Wanda Carney (as administrator)                -->

  <!-- ===================================================================== -->

  <Sequence
name="Login Parameters">
    <Set
parameter="testuser"         value="{~useradminid0~}" />
    <Set
parameter="testuser_pwd"     value="{~useradminid0_pwd~}" />
    <Set parameter="testuser_email"   value="{~useradminid0_email~}" />
    <Set
parameter="appname"          value="{~cloudapp~}" />
    <Set
parameter="contactemail"     value="{~cloudappuser~}" />
  </Sequence>

  <Sequence
filename="PUBLIC/COMMON/APP/Sequences/COMMON_APP_LicenseAppForUser"
            
username="{~testuser~}" password="{~testuser_pwd~}" />

  <!-- ===================================================================== -->
  <!--  Create a new logbook as Wanda Carney                                 -->

  <!-- ===================================================================== -->

  <Sequence
name="Login Parameters">
    <Set
parameter="testuser"         value="{~userid1~}" />
    <Set
parameter="testuser_pwd"     value="{~userid1_pwd~}" />
    <Set
parameter="testuser_email"   value="{~userid1_email~}" />
  </Sequence>

  <Sequence
filename="Sequences/createlogbook"
            
username="{~testuser~}" password="{~testuser_pwd~}"/>

  <!-- ===================================================================== -->
  <!--  Clean up as Wanda Carney                                             -->

  <!-- ===================================================================== -->

  <Sequence
name="Login Parameters">
    <Set
parameter="testuser"         value="{~userid1~}" />
    <Set
parameter="testuser_pwd"     value="{~userid1_pwd~}" />
    <Set
parameter="testuser_email"   value="{~userid1_email~}" />
  </Sequence>

  <Sequence
filename="Sequences/cleanup"
            
username="{~testuser~}" password="{~testuser_pwd~}" />
</Test>

Now create a sequence file by selecting “File” > “New” > “Sequence” and enter createlogbook.ducx-seq in the File name field of the dialog box and click “Finish”. After that, copy the source code from the following example into the createlogbook.ducx-seq file.

Example

createlogbook.ducx-seq

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Sequence name="logbook">
  <!--  Login -->
  <Set
parameter="portal"             value="{~deskportal~}" />
  <UseCase
filename="PUBLIC/COMMON/INITIALIZE/UseCases/COMMON_INITIALIZE_Login" />

  <!-- Activate Cloud App -->
  <Set
parameter="appname"            value="{~cloudapp~}" />
  <Set
parameter="appactivate"        value="true" />
  <UseCase
filename="PUBLIC/COMMON/APP/UseCases/COMMON_APP_ActivateAppForUser" />

  <!-- Create Teamroom -->
  <Set
parameter="portal"             value="{~deskportal~}" />
  <Set
parameter="tc"                 value="{~tc~}" />
  <UseCase
filename="PUBLIC/COMMON/TESTCONTAINER/UseCases/COMMON_TESTCONTAINER_
                     CreateTC_Teamroom" />

  <!-- Invoke the use case for creating a logbook in the Teamroom -->
  <Set
parameter="portal"             value="{~deskportal~}" />
  <Set
parameter="tc"                 value="{~tc~}" />
  <UseCase
filename="UseCases/createlogbook" />
</Sequence>

In the next step, create a use case file by selecting “File” > “New” > “Use Case” and enter createlogbook.ducx-case in the File name field of the dialog box and click “Finish”. Then click the “Start/Stop Recorder” button in the “Outline” view to bring up the dialog box.

Figure 51: Starting the Fabasoft app.test recorder

In the Address field on the “Run” page, enter the URL of your Cloud Sandbox. You can also use the {~webserver~} variable when defining the URL, as illustrated by the example.

On the Login page, enter the user name and password of the user you want to use for creating your test. For our example, we enter carney0001 in the {~username~} field and the password we defined for the test users in the {~password~} field (see chapter “Working with the Cloud App VDE”). Then click “OK” to start the recorder.

In the Fabasoft app.test recorder click the “Start Recording”’ button to start recording your interactions with the Cloud Sandbox. Once in recording mode, every mouse click and every push of a button is recorded and transformed into the corresponding statement, which is appended to the createlogbook.ducx-case file until you stop recording by clicking “Stop Recording”.

In order to keep the example concise, we’ll just carry out a few steps:

  • Create a new Teamroom and enter the Teamroom by double-clicking on it. In our createlogbook.ducx-seq sequence file, we’re using a common use case for creating a new Teamroom. Therefore, we don’t need to record the steps for creating the Teamroom.
  • Click the “Start Recording” button to start recording the executed steps.
  • Create a new logbook named “Team Logbook” inside of the Teamroom.
  • Enter “TEAM1” in the Vehicle ID property of the logbook.
  • Click “Next” to save and close the logbook.

When you’re done, click the “Stop Recording” button and switch to the source view of the createlogbook.ducx-case file, which should look like the following example.

Example

createlogbook.ducx-case

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<UseCase name="createlogbook">
  <Execution
action="Click" location="PAGES.Main.Contents.BUTTONBAR.New"/>
  <Execution action="Click" location="PAGES.Main.What do you want to create?.All"/>
  <Execution
action="Click" location="PAGES.Main.What do you want to create?[0].
                                      Logbook"/>

  <Execution
action="Click" location="PAGES.Main.BUTTONBAR.Next"/>
  <Execution
action="Set" location="PAGES.Main.Name" value="Team Logbook"/>
  <Execution
action="Set" location="PAGES.Main.Vehicle ID" value="TEAM1"/>
  <Execution
action="Click" location="PAGES.Main.BUTTONBAR.Next"/>
</UseCase>

In the next step, we’ll have to do some editing to make our use case compatible with the requirements of the Continuous Integration (CI) environment (see chapter “Continuous integration environment”) and to give it the finishing touches.

The main aspects of creating robust test use cases are discussed in great detail in [Faba19c], so we’ll limit ourselves to the most crucial things to keep in mind:

  • Use variables for any values you’re planning to use repeatedly. Most importantly, use variables for the names of your test containers (e.g. the Teamroom and the logbook) and include the testid variable in the names.
  • At the end of the use case, return to the starting point. In our example this means going back to the “Home” screen.

The following example shows the source code of the createlogbook.ducx-case file after incorporating all of the mentioned points.

Example

createlogbook.ducx-case

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<UseCase name="createlogbook">
  <!-- ===================================================================== -->
  <!--  Parameters                                                           -->

  <!-- ===================================================================== -->

  <Set parameter="tmpportal"        value="{~portal~}" />
  <Set
parameter="tmptc"            value="{~tc~}" />
  <Set
parameter="tmplogbook        value="Team Logbook {~testid~}" />

  <!-- Set defaults-->
  <Set
parameter="tmpportal"        value="{~deskportal~}"
    
if='"{~tmpportal~}"=="NULL" || "{~tmpportal~}"==""' />

  <!-- ===================================================================== -->
  <!--  Create logbook within Teamroom                                      -->

  <!-- ===================================================================== -->

  <Execution action="Click" location="PORTALS.{~tmpportal~}" />
  <Execution
action="Click" location="BREADCRUMBS[1]"/>

  <!-- Enter Teamroom -->
  <Set parameter="tmptcexists" location='PAGES.Main.CONTROLS.Contents["{~tmptc~}"]'
      
eval="Exists"/>
  <Validation
ok='"{~tmptcexists~}"=="true"' />
  <Execution
action="Doubleclick" location='PAGES.Main.CONTROLS.
                                            Contents["{~tmptc~}"]' />

  <!-- Create logbook -->
  <Execution
action="Click" location="PAGES.Main.Contents.BUTTONBAR.New"/>
  <Execution
action="Click" location="PAGES.Main.What do you want to create?.All"/>
  <Execution
action="Click" location="PAGES.Main.What do you want to create?[0].
                                      Logbook"/>

  <Execution
action="Click" location="PAGES.Main.BUTTONBAR.Next"/>
  <Execution
action="Set" location="PAGES.Main.Name" value="{~tmplogbook~}"/>
  <Execution
action="Set" location="PAGES.Main.Vehicle ID" value="TEAM1"/>
  <Execution
action="Click" location="PAGES.Main.BUTTONBAR.Next"/>

  <!-- Return to "Home" screen -->
  <Execution
action="Click" location="BREADCRUMBS[1]"/>
</UseCase>

Now that we’ve got you started, it’s up to you to improve your test and enrich it with additional use cases to cover all the functionality of your Cloud App not already covered by unit tests. Of course, it doesn’t hurt if your Fabasoft app.test tests also cover parts of your code that are already covered by unit tests.

Don’t forget to clean up when you’re done (i.e. create a sequence file named cleanup.ducx-seq and delete all the objects created by your use cases in a cleanup use case) to leave the test environment in a clean state.

The examples presented in this chapter should have given you a rough idea of how to create test use cases. For detailed information and a full language reference refer to the Fabasoft app.test online help (https://help.apptest.fabasoft.com), [Faba19b] and [Faba19c].

Also, the complete set of tests for our sample is available to you in the public Subversion repository of Fabasoft (https://cloud.fabasoft.com/svn/public). For further information refer to the chapter “Retrieving code samples from the public Subversion repository”.

Running a testPermanent link for this heading

To run your test, select the logbook.ducx-test file in Project Explorer of Fabasoft app.test, open the context menu and select “Run” to bring up the dialog box. Then click “OK” to start the test.

Figure 52: Running a test

Don’t close the window that is opened as this will abort the execution of your test. At the end of the test, a summary will be displayed in the “Test State” view.

For further information on running a test refer to the Fabasoft app.test online help (https://help.apptest.fabasoft.com), [Faba19b] and [Faba19c].

Checking and improving the coverage of your testsPermanent link for this heading

As you already know, one of your main objectives is to reach 100 % code coverage. But how can you find out which parts of your code are already covered by your tests?

Well, Fabasoft app.ducx includes a built-in coverage plug-in that makes it a breeze to determine the coverage ratio for your Cloud App.

Did you already notice the “Coverage” view displayed by default in the right bottom panel of Eclipse? If it’s not open for some reason, select “Window” > “Show View” > “Other”, select “Coverage” from the “Fabasoft app.ducx Coverage” branch and click “OK”.

These are the steps to record coverage information:

  • To start a coverage session, click the “Start Coverage Session” button (to the left of the “Hide/Show Coverage” button).
  • The web browser is launched and you are prompted to log in to your Cloud Sandbox.
  • During a coverage session, all of your actions and clicks (and also the actions carried out by unit tests and Fabasoft app.test tests) are recorded by the coverage plug-in.
  • When you stop the coverage session by clicking the “Stop Coverage Session” button, the recorded information is downloaded to Eclipse and you can drill down in your code to find the parts that have not been covered by your tests yet.

Coverage only applies to Fabasoft app.ducx expression code. Lines covered by a test are displayed in green whereas lines that have not been covered are displayed in red. Also, the number of times a line was visited during a coverage session is displayed.

Note: During a coverage session, every interaction with your Cloud Sandbox is recorded. When you run a Fabasoft app.test test against your Cloud Sandbox while a coverage session is active, the actions carried out by the test are also recorded.

Remember that coverage information is not user-specific. Every action carried out by any user in your Cloud Sandbox is taken into account for the coverage ratio.

To achieve a complete picture of the combined coverage ratio for your Cloud App, we suggest the following approach:

  • Start a new coverage session by clicking the “Start Coverage Session” button.
  • Log in using the “developer” user account.
  • From within an administration tool, execute all of your unit tests.
  • Switch to Fabasoft app.test primo and run your test.
  • Wait until your Fabasoft app.test test finishes.
  • Click the “Stop Coverage Session” button.
  • Examine the coverage information displayed in the “Coverage” view.

Note: Ant builds allow you to automate these manual steps. For further information refer to chapter “Automating builds with Apache Ant”.

Figure 53: Checking the coverage

Automating builds with Apache AntPermanent link for this heading

Fabasoft app.ducx integrates the Apache Ant library, which allows you to trigger automated builds driven by so-called build files.

But what exactly can you do with it?

Well, running Ant builds saves time. At the push of a button, you can have Apache Ant execute the following, fully customizable steps:

  1. Compile your Cloud App
  2. Deploy your Cloud App into your Cloud App VDE
  3. Start a coverage session
  4. Execute your unit tests
  5. Stop the coverage session and download the coverage information
  6. Generate a report presenting the unit test results

The skeleton project generated for your Cloud App already contains the sample build file build.xml.

Before you can run an Ant build, you have to make some modifications to the build.xml file. As shown in the example, provide the URL of your Cloud Sandbox in the cloudsandboxurl parameter and the password for the “developer” account in the password parameter.

Example

build.xml

<?xml version="1.0" encoding="utf-8"?>
<project name="FSCLOGBOOK" default="quick" basedir=".">
  
<!-- Global Properties -->
  <property name=
"devdir" value="${basedir}"/>
  <property name="testdir" value="${basedir}/../test"/>
  <property name=
"cloudsandboxurl" value="https://vde.fabasoft.com/dev2/vm23/folio"/>
  <property name=
"user" value="developer"/>
  <property name=
"password" value="TODO: enter your password here"/>

  <target name="definewebsvc">
    <ducx.webservice id=
"websvc" url="${cloudsandboxurl}" timeout="5">
      <authentication>

        <basic user=
"${user}" password="${password}"/>
      </authentication>

    </ducx.webservice>

  </target>

  
<!-- Quick Compile -->
  <target name="quick" depends="definewebsvc">
    <ducx ducxproject=
"${devdir}/.ducxproject" verbose="true">
      <webservice refid=
"websvc"/>
      <clean/>

      <compile copyright=
"${devdir}/copyright.txt"/>
      <load/>

    </ducx>

  </target>

  <!-- Full Compile -->
  <target name="compile" depends="definewebsvc">
    <ducx ducxproject=
"${devdir}/.ducxproject" verbose="true">
      <webservice refid=
"websvc"/>
      <clean/>

      <updaterefs/>

      <cleanlangfiles copyright=
"${devdir}/copyright.txt"/>
      <compile copyright=
"${devdir}/copyright.txt"/>
      <load/>

    </ducx>

  </target>

  
<!-- Run Unit Tests -->
  <target name=
"unittest" depends="definewebsvc">
    <ducx.startcoverage session=
"coverage-session-id" verbose="true">
      <webservice refid=
"websvc"/>
      <cover>
FSCLOGBOOK@111.100</cover>
    </ducx.startcoverage>

    <ducx.unittest todir="${devdir}/results/unit">
      <webservice refid=
"websvc"/>
      <evaluate>
FSCLOGBOOK@111.100:UTGLogbook</evaluate>
    </ducx.unittest>

    <ducx.stopcoverage session="${coverage-session-id}" verbose="true"
      target=
"${devdir}/results/coverage">
      <webservice refid=
"websvc"/>
    </ducx.stopcoverage>

    <junitreport todir="${devdir}/results/unit">
      <fileset dir=
"${devdir}/results/unit">
        <include name=
"ducxunittest-*.xml"/>
      </fileset>

      <report format=
"noframes" todir="${devdir}/reports"/>
    </junitreport>

  </target>

</project>

After modifying the build.xml file, select “External Tools Configurations” from the “External Tools” menu in Eclipse. Select “Ant Build”, click the “New launch configuration” symbol and enter a Name for the new launch configuration, e.g. “FSCLOGBOOK Build and Test”.

On the “Main” page, click the “Browse Workspace” button of the Buildfile field and select the build.xml file. Switch to the “Targets” page and select the “quick” and “unittest” targets in the Check targets to execute field. Finally, switch to the “JRE” page and select “Run in the same JRE as the workspace” in the Runtime JRE field. Then click “Apply” to save your changes and “Run” to trigger the Ant build. The results of the Ant build are shown in the “Console” view of Eclipse.

Figure 54: Creating an Ant build configuration

Figure 55: Log output of an Ant build

After the Ant build has finished, select “Refresh” from the context menu of your Cloud App project and you should see two new folders, reports and results.

In the reports folder, you will find a unit test report similar to the one shown in the following figure.

Figure 56: Unit test report

The results of the coverage session are provided in a subfolder of the coverage folder in the reports folder. To analyze the coverage data, click “Open a Coverage Session” in the “Coverage” view and select the corresponding coverage session file.

Of course you can further customize the build file according to your needs, and add or modify targets as you see fit. Furthermore, you can use Apache Ant to build multiple Cloud Apps in a single build.

Refer to [Faba19a] and [ApAn18] for further information about Apache Ant and build files.