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:
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 thecrm
project. Do so by select the the projectcrm
as Required Project inside the creation wizard (or later over: Definitions -> Deployment -> Required Projects).
Convert Projects to Maven Projects
Open the Package Explorer (Windows -> Show View -> Other -> Package Explorer)
Within the Package Explorer, convert both projects (
crm
andcrmIntegrationTests
) to Maven Projects. (Right click on the project -> Configure -> Convert to Maven Project).
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 thecrmIntegrationTests
project (Right click on the project -> New -> Folder)
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>
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() { } }
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"));
}
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:
Create maven module
Delete projects
crm
andcrmIntegrationTests
from your Designer workspace.Open your workspace folder and move both projects into an new folder, e.g
compile-test
Add
pom.xml
file intocompile-test
folder.Add following to the pom.xml file (ensure the correct modules
crm
andcrmIntegrationTests
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
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
andcrmIntegrationTests
should be visible here) and click FinishRight-click on
compile-test
-> Run As -> Maven buildSet Goals to
clean verify
and click RunThis 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:
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>
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>
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.
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>
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>
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.