---
title: "Model-Based Testing using GraphWalker and Java"
canonical: "https://docs.getxray.app/space/XRAY/301673330/Model-Based%20Testing%20using%20GraphWalker%20and%20Java"
format: markdown
---
> Macro (toc)

# Overview

[GraphWalker](https://graphwalker.github.io/) is a tool that addresses State Transition Model-Based Testing; in other words, it allows you to perform modeling around states and transitions between those states using directed graphs. 

![image](media://08ea7825-92d8-4729-8f4b-22aaf0448546)


Here is some clarification around some key concepts using the information provided by GraphWalker's documentation that explains them clearly:

- **edge**: *An edge represents an action, a transition****. ****An action could be an API call, a button click, a timeout, etc. Anything that moves your System Under Test into a new state that you want to verify. But remember, there is no verification going on in the edge. That happens only in the vertex.*
- **vertex:  ***A vertex represents verification, an assertion. A verification is where you would have assertions in your code. It is here that you verify that an API call returns the correct values, that a button click actually did close a dialog, or that when the timeout should have occurred, the System Under Test triggered the expected event.*
- **model**: *A model is a graph, which is a set of vertices and edges.*


*From a model, GraphWalker will generate a ****path**** through it. A model has a ****start element****, and a ****generator**** which rules how the path is generated, and associated**** stop condition**** which tells GraphWalker when to stop generating the path.*


Generators and stop conditions are essential in GraphWalker (more info [here](https://github.com/GraphWalker/graphwalker-project/wiki/Test-path-generation) and [here](https://github.com/GraphWalker/graphwalker-project/wiki/Generators-and-stop-conditions)), as they influence how the model will be "walked" and until when.

Multiple models can interact with one another (i.e. jump from one to other and vice-versa), using shared states (i.e. vertices that have a "shared name").

Each model has an internal state with some variables - its **context**. Besides, and since GraphWalker can transverse multiple models, there is also a **global context**.


We can also add actions and guards to the model, which can affect how the model is walked and how it behaves:

- **action**: a way of setting variables in the model or global context; actions are implemented using JavaScript
- **guard**: a way of blocking/guard edges from being walked/executed, usually considering variables stored in the model or global context; guards are implemented using JavaScript.


In sum, we model (i.e. build a model) a certain aspect related to our system using directed graphs; the model represents a test idea that describes expected behaviors. Checks are implemented in the vertices (i.e. states) and actions are performed in the edges. GraphWalker will then "walk" the model (i.e. perform a set of "steps"/edges) using a generated path. While doing so, it looks at JavaScript guards to check if edges can be "walked" and performs JavaScript based *actions* to set internal context variables . It stops "walking" if stop condition(s) are met.

To build the model, we can use a visual tool and ([GraphWalker Studio](https://github.com/GraphWalker/graphwalker-project/wiki/GraphWalker-Studio)) and export it to a JSON file.

## Mapping concepts to Xray

### Tests

Besides other entities, in Xray we have Test issues and "requirements" (i.e. issues that can be covered with Tests).

In GraphWalker, the testing is performed continuously by walking a path (as a result of its generator) and until certain condition(s) is(are) met.

This is a bit different from traditional, sequential test scripts where each one has a set of well-defined actions and expected results.

We can say that GraphWalker produces dynamic test cases, where each one corresponds to the full path that was generated. Since the number of possible paths can be quite high, we can follow a more <u>straightforward approach: consider each model a Test, no matter exactly what path is executed</u>. Remember that a model in itself is a high-level test idea, something that you want to validate; therefore, this seems a good fit as long as we have the means to later on debug it.

### Requirements

What about "requirements"?

Well, even though GraphWalker allows you to assign one or more requirement identifiers to each vertex, it may not be the most suitable approach linking our model (or parts of it) to requirements. Therefore, and since we consider the model as a Test, we can eventually link each model to a "requirement" later on in Jira.

### Results

In sequential scripted automated tests/checks, we look at the expectation(s) using assert(s) statement(s), after we perform a set of well-known and predefined actions. Therefore, we can clearly say that the test scenario exercised by that test either passed or failed.

In MBT, especially in the case of State Transition Model-Based Testing, we start from a given vertex but then the path, that describes the sequence of edges and vertices visited, can be quite different each time the tool generates it. Besides, the stop condition is not composed by one or more well-known and fixed expectations; it's based on some more graph/model related criteria.

When we "execute the model", it will walk the path (i.e. go over from vertex to vertex through a given edge) and performing checks in the vertices. If those checks are successful until the stop condition(s) is achieved, we can say that it was successful; otherwise, the model is not a good representation of the system as it is we can say that it "failed."

# Example

In this tutorial, we'll use an example provided by the GraphWalker community (please check [GraphWalker wiki page describing it](https://github.com/GraphWalker/graphwalker-project/wiki/PetClinic)) which targets the well-known [PetClinic sample site](https://github.com/spring-projects/spring-petclinic/).

![image](media://e7b55d20-5c62-46e5-90e0-6a6558fbbf8b)


<u>Requirements</u>

- Java 8
- PetClinic sample application (requires Java 8 as it is)
  - `git clone https://github.com/SpringSource/spring-petclinic.gitcd spring-petclinicgit reset --hard 482eeb1c217789b5d772f5c15c3ab7aa89caf279mvn tomcat7:run`
- GraphWalker
- GraphWalker Studio


How can we test the PetClinic website using MBT technique?

Well, one approach could be to model the interactions between different pages. Ultimately they represent certain features that the site provides and that are connected with one another.

In this example, we'll be using these:

- **PetClinic**: main model of the PetClinic store, that relates several models provided by different sections in the site
- **FindOwners**: model around the feature of finding owners
- **Veterinarians**:  model around the feature of listing veterinarians
- **OwnerInformation**: model around the ability of showing information/details of a owner
- **NewOwner**: model around the feature of creating a new owner


> ℹ️ **Please note**
> ℹ️ 
> ℹ️ Remember that you could model it completely differently; modeling represents a perspective.


Models can be built using [GraphWalker Studio](https://github.com/GraphWalker/graphwalker-project/wiki/GraphWalker-Studio). We can use it to load previously saved model(s) like the ones in [PetClinic.json](https://github.com/GraphWalker/graphwalker-example/blob/master/java-petclinic/src/main/resources/com/company/PetClinic.json). In this case, the JSON file contains several models; we could also have one JSON file per model.

The following picture shows the overall PetClinic model, that interacts with other models.

![image](media://e5211d72-2950-4ce1-99e5-e71c3709d583)

GraphWalker Studio allow us to run the model in offline, i.e. without executing the underlying test automation code, so we can validate it.



Let's pick the NewOwner model as an example, which is quite simple.

"v_NewOwner" represents, accordingly to what we've defined for our model, being on the "New Owner" page.

If we fill correct data (i.e. using the edge "e_CorrectData"), we'll be redirected to a page showing the owner information. 

Otherwise, if we fill incorrect data (i.e. using the edge "e_IncorrectData") an error will be shown and the user keeps on the "New Owner" page.


![image](media://8969b995-d346-430c-8e16-7740586f0a9c)



> ℹ️ **Please note**
> ℹ️ 
> ℹ️ <span style="color: #222222">Usually, to implement the automation code we would create a Maven project from scratch, copy the model file(s), and generate a skeleton of the sources for our model.</span>
> ℹ️ 
> ℹ️ <span style="color: #222222">To do so, we would perform something such as:</span>
> ℹ️ 
> ℹ️ 
> ℹ️ <span style="color: #222222"># generate a Maven project prepared for GraphWalker</span>  
> ℹ️ mvn archetype:generate -B -DarchetypeGroupId=org.graphwalker -DarchetypeArtifactId=graphwalker-maven-archetype -DgroupId=com.company -DartifactId=myProject  
> ℹ️   
> ℹ️ # store the JSON of the model(s) in src/main/resources/   
> ℹ️ ...
> ℹ️ 
> ℹ️   
> ℹ️ <span style="color: #222222"># generate a skeleton of an implementable interface</span>  
> ℹ️ <span style="color: #222222">mvn graphwalker:generate-sources</span>


The Java class that implements the edges and vertices of this model is defined in the class [NewOwnerTest](https://github.com/GraphWalker/graphwalker-example/blob/master/java-petclinic/src/main/java/com/company/modelimplementations/NewOwnerTest.java). Actions performed in the edges are quite simple. Assertions are also simple as they're only focused on the state/vertex they are at.

<details>
<summary>class implementing the model "NewOwner"</summary>

```java
package com.company.modelimplementations;

import com.company.NewOwner;
import com.github.javafaker.Faker;
import org.graphwalker.core.machine.ExecutionContext;
import org.graphwalker.java.annotation.GraphWalker;
import org.openqa.selenium.By;

import static com.codeborne.selenide.Condition.text;
import static com.codeborne.selenide.Condition.visible;
import static com.codeborne.selenide.Selenide.$;
import static com.codeborne.selenide.Selenide.$x;

/**
 * Implements the model (and interface) NewOwnerSharedState
 * The default path generator is Random Path.
 * Stop condition is 100% coverage of all edges.
 */
@GraphWalker(value = "random(edge_coverage(100))")
public class NewOwnerTest extends ExecutionContext implements NewOwner {

    @Override
    public void v_OwnerInformation() {
        $(By.tagName("h2")).shouldHave(text("Owner Information"));
        $x("/html/body/div/table[last()]/tbody/tr/td[2]/img").shouldBe(visible);
    }

    @Override
    public void e_CorrectData() {
        fillOwnerData();
        $(By.id("telephone")).sendKeys(String.valueOf(new Faker().number().digits(10)));
        $("button[type=\"submit\"]").click();
    }

    @Override
    public void e_IncorrectData() {
        fillOwnerData();
        $(By.id("telephone")).sendKeys(String.valueOf(new Faker().number().digits(20)));
        $("button[type=\"submit\"]").click();
    }

    @Override
    public void v_IncorrectData() {
        $(By.cssSelector("div.control-group.error > div.controls > span.help-inline"))
                .shouldHave(text("numeric value out of bounds (<10 digits>.<0 digits> expected)"));
    }

    @Override
    public void v_NewOwner() {
        $(By.tagName("h2")).shouldHave(text("New Owner"));
        $x("/html/body/table/tbody/tr/td[2]/img").shouldBe(visible);
    }

    private void fillOwnerData() {
        $(By.id("firstName")).clear();
        $(By.id("firstName")).sendKeys(new Faker().name().firstName());

        $(By.id("lastName")).clear();
        $(By.id("lastName")).sendKeys(new Faker().name().lastName());

        $(By.id("address")).clear();
        $(By.id("address")).sendKeys(new Faker().address().fullAddress());

        $(By.id("city")).clear();
        $(By.id("city")).sendKeys(new Faker().address().city());

        $(By.id("telephone")).clear();
    }
}
```
</details>


In the previous example, we can see that the class NewOwnerTest extends ExecutionContext; this ties the model with the path generator and provides a context for tracking the internal state and history of the model.

The **@GraphWalker** annotation is used to specify the path generator and stop conditions. This is used for *online* path generation during test execution. 

If follows this syntax:

       <span style="color: #d73a49">@GraphWalker</span><span style="color: #24292e">(</span><span style="color: #005cc5">value</span><span style="color: #24292e"> </span><span style="color: #d73a49">=</span><span style="color: #24292e"> </span><span style="color: #032f62">"generator(stop_conditions)", </span><span style="color: #005cc5">start</span><span style="color: #24292e"> </span><span style="color: #d73a49">=</span><span style="color: #24292e"> "start_element", </span><span style="color: #005cc5">groups</span><span style="color: #24292e"> </span><span style="color: #d73a49">=</span><span style="color: #24292e"> { "group" }  )</span>

<span style="color: #24292e">such as:</span>

<span style="color: #d73a49">@GraphWalker</span><span style="color: #24292e">(</span><span style="color: #005cc5">value</span><span style="color: #24292e"> </span><span style="color: #d73a49">=</span><span style="color: #24292e"> </span><span style="color: #032f62">"</span><span style="color: #032f62">random(reached_vertex(v_ShoppingCart))</span><span style="color: #032f62">"</span><span style="color: #24292e">, </span><span style="color: #005cc5">start</span><span style="color: #24292e"> </span><span style="color: #d73a49">=</span><span style="color: #24292e"> </span><span style="color: #032f62">"</span><span style="color: #032f62">e_StartBrowser</span><span style="color: #032f62">", </span><span style="color: #005cc5">groups</span><span style="color: #24292e"> </span><span style="color: #d73a49">=</span><span style="color: #24292e">  { "default" } </span><span style="color: #24292e">)</span>



> ℹ️ **Please note**
> ℹ️ 
> ℹ️ Tests using the model can also be created and executed programmatically similar to other tests, using JUnit or other testing framework. More info [here](https://github.com/GraphWalker/graphwalker-project/wiki/Test-execution) and [here](https://gw4e.github.io/mydoc_nutshell.html).
> ℹ️ 
> ℹ️ The flow would be something like:
> ℹ️ 
> ℹ️ 1. create a TestBuilder object
> ℹ️ 2. create a Context object
> ℹ️ 3. add the Context to the TestBuilder
> ℹ️ 4. execute it, using .execute()
> ℹ️ 5. optionally, look at the Result object returned to see if it has errors, using .hasErrors()
> ℹ️ 
> ℹ️ 
> ℹ️ ##### **example of some Tests implementing using JUnit**
> ℹ️ 
> ℹ️ ```java
> ℹ️ public class SimpleTest extends ExecutionContext implements Login {
> ℹ️     public final static Path MODEL_PATH = Paths.get("org/myorg/testautomation/Login.json");
> ℹ️ ...
> ℹ️     @Test
> ℹ️     public void runSmokeTest() {
> ℹ️         new TestBuilder()
> ℹ️                 .addContext(new SimpleTest().setNextElement(new Edge().setName("e_Init").build()),
> ℹ️                         MODEL_PATH,
> ℹ️                         new AStarPath(new ReachedVertex("v_Browse")))
> ℹ️                 .execute();
> ℹ️     }
> ℹ️ 
> ℹ️     @Test
> ℹ️     public void runFunctionalTest1() {
> ℹ️         new TestBuilder()
> ℹ️                 .addContext(new SimpleTest().setNextElement(new Edge().setName("e_Init").build()),
> ℹ️                         MODEL_PATH,
> ℹ️                         new RandomPath(new EdgeCoverage(100)))
> ℹ️                 .execute();
> ℹ️     }
> ℹ️ 
> ℹ️     @Test
> ℹ️     public void runFunctionalTest2() {
> ℹ️         TestBuilder builder = new TestBuilder()
> ℹ️                 .addContext(new SimpleTest().setNextElement(new Edge().setName("e_Init").build()),
> ℹ️                         MODEL_PATH,
> ℹ️                         new RandomPath(new EdgeCoverage(100)));
> ℹ️         Result result = builder.execute(true);
> ℹ️         Assert.assertFalse(result.hasErrors());
> ℹ️     }
> ℹ️ 
> ℹ️     @Test
> ℹ️     public void runStabilityTest() {
> ℹ️         new TestBuilder()
> ℹ️                 .addContext(new SimpleTest().setNextElement(new Edge().setName("e_Init").build()),
> ℹ️                         MODEL_PATH,
> ℹ️                         new RandomPath(new TimeDuration(30, TimeUnit.SECONDS)))
> ℹ️                 .execute();
> ℹ️     }
> ℹ️ }
> ℹ️ ```
> ℹ️ 
> ℹ️ 
> ℹ️ In this case, we could execute the tests using Maven. We would then use the JUnit XML report produced by JUnit itself.
> ℹ️ 
> ℹ️ `mvn test`



To run the tests online with GraphWalker we can use Maven, since there is a specific plugin for assisting with this. This will produce a single JUnit XML report stored in the `target/graphwalker-reports/` directory.

##### **example of a Bash script to run the tests**

```shell
rm -f target/graphwalker-reports/*.xml
mvn graphwalker:test
```


<span style="color: #172b4d">After successfully running the tests and generating the JUnit XML report</span><span style="color: #172b4d">, it can be imported to Xray (either by the </span>[<span style="color: #172b4d">REST API</span>](https://getxraydocs.atlassian.net/wiki/spaces/XRAY/pages/301667997)<span style="color: #172b4d"> or through the</span><span style="color: #172b4d"> </span>**Import Execution Results**<span style="color: #172b4d"> </span><span style="color: #172b4d">action within the Test Execution, or even by using a </span>[<span style="color: #172b4d">CI tool of your choice</span>](https://getxraydocs.atlassian.net/wiki/spaces/XRAY/pages/301468299)<span style="color: #172b4d">).</span>


##### **example of a Bash script to import the results**

```shell
REPORT_FILE=$(ls target/graphwalker-reports/TEST-GraphWalker-*.xml | sort | tail -n 1)
curl -H "Content-Type: multipart/form-data" -u admin:admin -F "file=@$REPORT_FILE" http://jiraserver.example/rest/raven/1.0/import/execution/junit?projectKey=CALC
```


![image](media://85a60346-15d7-46f9-91e4-68bd36fdab79)

<span style="color: #000000">Each model is mapped to JUnit's testcase element which in turn is mapped to a Generic Test in Jira, and the </span>**<span style="color: #000000">Generic Test Definition</span>**<span style="color: #000000"> field contains the name of the package and the class that implements the model related methods for edges and vertices. The summary of each Test issue is filled out with the name of the class.</span>

<span style="color: #000000">The Execution Details page also shows information about the Test Suite, which will be just "GraphWalker."</span>

![image](media://2023b8b4-d68b-4071-bfb7-d120ae5e5dec)

# Tips

- Use MBT not to replace existing test scripts but in cases where you need to provide greater coverage
- Discuss the model(s) with the team and the ones that can be most useful for your use case
- You can control the seed of the random generator used by GraphWalker, so you can easily reproduce bugs (i.e. by reproducing the generated path)
- You can use [GraphWalker Player](https://github.com/GraphWalker/graphwalker-player) to see the graph being walked in real-time. You can use a [sample HTML](https://github.com/GraphWalker/graphwalker-player/blob/master/index.html) file that contains the code to connect to a WebSocket server that you need to instantiate in the runner side ([example](https://github.com/GraphWalker/graphwalker-example/blob/master/java-petclinic/src/main/java/com/company/runners/WebSocketApplication.java)) .
  - Example:
    - open the file index.html in your browser, using an URL such as "file:///Users/you/index.html?wsURI=localhost:8887?wsURI=localhost:8887"
    - execute GraphWalker, using the [custom runner](https://github.com/GraphWalker/graphwalker-example/blob/master/java-petclinic/src/main/java/com/company/runners/WebSocketApplication.java)
      - `mvn exec:java -Dexec.mainClass="com.company.runners.WebSocketApplication" `
- Multiple runs of your tests can be grouped and consolidate in a Test Plan, so you can have an updated overview of their current state
- After importing the results, you can link the corresponding Test issues with an existing requirement or user story and thus track coverage directly on the respective issue, or even on an Agile board
    
  - 
    

# References

- [GraphWalker](https://graphwalker.github.io/)
- [GraphWalker documentation pages](https://github.com/GraphWalker/graphwalker-project/wiki)
- [GraphWalker model+code for testing the PetClinic site](https://github.com/GraphWalker/graphwalker-project/wiki/PetClinic)
- [Actions and Guards](https://altom.gitlab.io/altwalker/altwalker/how-tos/actions-and-guards.html) (from AltkWalker's documentation)
- [GraphWalker CLI](https://github.com/GraphWalker/graphwalker-project/wiki/Command-Line-Tool)
- [GraphWalker Player](https://github.com/GraphWalker/graphwalker-player)
- [GraphWalker plugin for Eclipse (GW4E)](https://gw4e.github.io/index.html)
- [GraphWalker and GW4E in a nutshell](https://gw4e.github.io/mydoc_nutshell.html)
- [Article on MBT](https://pragmatic-qa.com/state-transition-testing-with-graphwalker/)