Testing

Writing test code has a bad reputation, however they can make your life much easier. Think about the following points:

  • Tests can make the functionality of a software reliable

  • Quality can be maintained

  • Repetitive tasks can be reduced to a minimum. Let the computer do it!

  • Ensure that the software does what it supposed to do (e.g after a code change or even a platform update).

Write good software without tests is nearly impossible and we want give you the ability to write tests for your software as easy as possible. Let’s get started!

Web Testing

Consider the following use case: You have build a workflow app containing multiple user dialogs. Do you really want to click always through the full process, if you maybe change a part of it? At least you should make sure that the functionality (happy path) of this process is still ensured.

Web Integration tests will always follow the same steps and can be highly automated.

How to write a Web Test

The first step in writing your own web tests is to create a new test project.

Tip

The following guide is based on a demo project and uses the name crm for the project to be tested and the name crmIntegrationTests for the one containing the tests.

Since this documentation only shows how to setup a test project and perform a simple test, you should take a look at the demo project.

Setup test project

The following step-by-step instructions show you how to create a new test project:

  1. Add a new Axon.ivy Project

    • Enter the same name as the crm project but with a name postfix (e.g: crmIntegrationTests)

    • Make the crmIntegrationTests project depending on the crm project. Do so by select the the project crm as Required Project inside the creation wizard (or later over: Definitions -> Deployment -> Required Projects).

  2. Convert Projects to Maven Projects

    • Open the Package Explorer (Windows -> Show View -> Other -> Package Explorer)

    • Within the Package Explorer, convert both projects (crm and crmIntegrationTests) to Maven Projects. (Right click on the project -> Configure -> Convert to Maven Project).

  3. Define a test source directory

    • Open the .classpath file. This can be found if you disable the .* resource filter inside the Package Explorer (or open the file directory from the File Explorer).

    • Add the following lines to the .classpath file:

      <classpathentry kind="src" output="target/test-classes" path="src_test">
        <attributes>
          <attribute name="test" value="true"/>
          <attribute name="optional" value="true"/>
        </attributes>
      </classpathentry>
      
    • Add a new folder src_test to the crmIntegrationTests project (Right click on the project -> New -> Folder)

  4. Add test util dependencies

    • Open the pom.xml file of the crmIntegrationTests project (Right click on pom.xml or Deployment -> Open With -> Maven POM Editor)

    • Add the following dependency and repository to the pom.xml file:

      <dependencies>
        <dependency>
          <groupId>com.axonivy.ivy.webtest</groupId>
          <artifactId>web-tester</artifactId>
          <version>8.0.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
      
  5. Add a test class

    • Create a new class (e.g WebTestRegistrationForm) inside of the src_test folder (Right click on ‘src_test’ -> New -> Class, e.g ‘WebTest’ as name)

    • Add the following code inside:

      import static com.codeborne.selenide.Condition.*;
      import static com.codeborne.selenide.Selenide.*;
      
      import org.junit.jupiter.api.Test;
      import org.openqa.selenium.By;
      
      import com.axonivy.ivy.webtest.IvyWebTest;
      import com.axonivy.ivy.webtest.engine.EngineUrl;
      
      @IvyWebTest
      public class WebTestRegistrationForm
      {
        @Test
        public void registerNewCustomer()
        {
          
        }
      }
      
  6. Run test

    • Make sure the engine is started with your projects

    • To run this test right-clicking inside this class -> Run As -> JUnit Test

    • A new JUnit View should have been opened and the test should be green.

Write Web Test

Let’s start by extending our test class added above with a real test implementation. First we need to start a process (you can use the EngineUrl utility from the Web-Tester to do this).

This process opens a dialog with two input fields (firstname and lastname) and a submit button. After submitting, a second dialog with your inputs is displayed.

@Test
public void registerNewCustomer()
{
  //You can use the EngineUrl utility to get to the info page of you engine:
  open(EngineUrl.base());
  
  //Search for the process start link and click it
  $(By.linkText("customer/register.ivp")).shouldBe(visible).click();
  
  //Fill in new customer
  $(By.id("form:firstname")).sendKeys("Unit");
  $(By.id("form:lastname")).sendKeys("Test");
  
  //Check that the submit button is enabled, before click it.
  $(By.id("form:submit")).shouldBe(enabled).click();
  
  //Check that the registration was successful.
  $(By.id("form:newCustomer")).shouldBe(visible, text("Unit Test"));
}
../_images/webtesting-run.gif

Tip

The @IvyWebTest annotation can be configured (e.g to choose your browser or change if it should be started headless).

Select, Do and Check

Now let’s take a look how this test works. Basically, there are three things you need to know:

  • Select an element

  • Do an action with this selected element

  • Check a condition on this selected element

Select

To work with a single element you must first select the correct one. Normally you can use the By.id selector for this:

$(By.id("form:submit")); //Find element by id selector

Tip

To evaluate the real id of an element you can use the Developer Tools of your browser.

There are much more options how you can use selectors, e.g you can select multiple elements:

$$(By.cssClass("ui-outputlabel")); //Find all <p:outputLabel> elements

Take a look at the demo project to see what else is possible.

Do an action

On the selected element you can perform some actions:

$(By.id("form:submit")).click();            //click on button
$(By.id("form:lastname")).clear();          //clear input field
$(By.id("form:lastname")).sendKeys("Test"); //set input value
Check a condition

On your selected element you can check some conditions too (e.g is the element visible or contains a specific value):

$(By.id("form:lastname")).shouldHave(value("Test")); //input field should have value "Test"

Tip

You can check multiple conditions on an item or you can check something before perform an action on the item:

//button should be enabled before click on it
$(By.id("form:submit")).shouldBe(enabled).click();
//<h:outputText> element should be visible and have text "Unit Test"
$(By.id("form:newCustomer")).shouldBe(visible, text("Unit Test"));

Take a look at the demo project to see what else is possible.

Run automated

Now let’s look at how you can run your web tests automated (Continuous Integration). This is important if you want fast feedback on breaking changes, maybe introduced by a team member.

Module build

Both projects needs to be compiled in the same run. For this we need firstly to setup a maven module build:

  1. Create maven module

    • Delete projects crm and crmIntegrationTests from your Designer workspace.

    • Open your workspace folder and move both projects into an new folder, e.g compile-test

    • Add pom.xml file into compile-test folder.

    • Add following to the pom.xml file (ensure the correct modules crm and crmIntegrationTests are set):

      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>ch.ivyteam.ivy.project.demos.ci</groupId>
        <artifactId>crm.modules</artifactId>
        <version>8.0.5-SNAPSHOT</version>
        <packaging>pom</packaging>
        <modules>
          <module>crm</module>
          <module>crmIntegrationTests</module>
        </modules>
      </project>
      
    • Your folder structure should look like the following:

      workspace/
        compile-test/
          crm/
          crmIntegrationTests/
          pom.xml
      
  2. Run module build in IDE

    • In your Designer open the Import Wizard, then Existing Maven Projects

    • Select compile-test/pom.xml with sub projects (crm and crmIntegrationTests should be visible here) and click Finish

    • Right-click on compile-test -> Run As -> Maven build

    • Set Goals to clean verify and click Run

    • This should trigger a run which starts with something like:

      [INFO] Scanning for projects...
      [INFO] ------------------------------------------------------------------------
      [INFO] Reactor Build Order:
      [INFO] 
      [INFO] crm                                                                [iar]
      [INFO] mycrm-test                                                         [iar]
      [INFO] crm.modules                                                        [pom]
      

      But it ends with some Errors. To fix those let’s continue with the next steps.

Run integration tests

To run our tests within a maven build, we need to start an engine, deploy the crm project to it, and then stop the engine after the tests are finished. We can define these steps in the pom.xml file of our crmIntegrationTests project:

  1. Set test sources dir and test application name

    <properties>
      <test.application>CrmApplication</test.application>
    </properties>
    
    <build>
      <testSourceDirectory>src_test</testSourceDirectory>
      <testOutputDirectory>target/test-classes</testOutputDirectory>
      ...
    </build>
    
  2. Start an engine

    <plugin>
      <groupId>com.axonivy.ivy.ci</groupId>
      <artifactId>project-build-plugin</artifactId>
      <extensions>true</extensions>
      <executions>
        <execution>
          <id>start.test.engine</id>
          <phase>pre-integration-test</phase>
          <goals>
            <goal>start-test-engine</goal>
          </goals>
        </execution>
        ...
      </executions>
    </plugin>
    
  3. Deploy our crm project to the engine

    <plugin>
      <groupId>com.axonivy.ivy.ci</groupId>
      <artifactId>project-build-plugin</artifactId>
      <extensions>true</extensions>
      <executions>
        ...
        <execution>
          <id>deploy-test-application</id>
          <phase>pre-integration-test</phase>
          <goals>
            <goal>deploy-to-engine</goal>
          </goals>
          <configuration>
            <deployFile>../crm/target/crm-${project.version}.iar</deployFile>
            <deployToEngineApplication>${test.application}</deployToEngineApplication>
            <skipDeploy>${maven.test.skip}</skipDeploy>
          </configuration>
        </execution>
        ...
      </executions>
    </plugin>
    

    Tip

    In the demo project we use the dependency plugin to evaluate the deployFile attribute.

  4. Stop the engine after the tests are finished

    <plugin>
      <groupId>com.axonivy.ivy.ci</groupId>
      <artifactId>project-build-plugin</artifactId>
      <extensions>true</extensions>
      <executions>
        ...
        <execution>
          <id>stop.test.engine</id>
          <phase>post-integration-test</phase>
          <goals>
            <goal>stop-test-engine</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    
  5. Add the test runner plugin

    <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>3.0.0-M4</version>
      <executions>
        <execution>
          <id>selenium.web.tests</id>
          <phase>integration-test</phase>
          <goals>
            <goal>test</goal>
          </goals>
          <configuration>
            <includes>
              <include>**/WebTest*.java</include>
            </includes>
            <argLine>
              -Dtest.engine.url=${test.engine.url}
              -Dtest.engine.app=${test.application}
            </argLine>
          </configuration>
        </execution>
      </executions>
    </plugin>
    
  6. Run module build in IDE

    • Try to run the module build as before in second step of the Module build section. The build should now succeed.

Further Resources

If you want to know more about web testing, take a look at the second test in our demo project or at our other demo projects and how they are tested.

If you want to learn more about how to build a CI/CD pipeline, take a look at the CI/CD videos in our Tutorial section.

Selenium

Selenium is open source and works across different browsers and platforms. To communicate with the browser, selenium provides the WebDriver specification.

In our tests we use the Selenide (GitHub, API) framework, which is based on the Selenium WebDriver. If you’re more familiar with plain Selenium tests the following comparison can give you a quick overview about the differences and benefits: Selenide vs Selenium. Or you can simply write your tests with the normal Selenium API by accessing the driver object:

WebDriver driver = WebDriverRunner.getWebDriver();

Web-Tester

With the web-tester we provide you the annotation @IvyWebTest, which sets up the browser connection for you. It can be configured with some parameters:

//Default (same as simple @IvyWebTest)
@IvyWebTest(browser = "firefox", headless = true, reportFolder = "target/selenide/reports")
  • browser: The browser which should run the test e.g: chrome, firefox, ie, phantomjs, htmlunit, safari, opera

  • headless: Controls if the browser should start with a UI or not.

  • reportFolder: Automatic screenshots will be taken, when a test fails. This folder defines where they are saved.