Using TestProject Actions in Our Test Classes

After we have have written custom TestProject actions, we want to use them in our test classes. Unfortunately, we have no idea how can do it.

During this blog post we will write two tests for the search function of my blog and both test classes use the custom actions which we wrote in the previous parts of my TestProject tutorial.

After we have finished this blog post, we:

  • Know how we can download a TestProject addon proxy.
  • Understand how we can use the actions provided by the downloaded addon proxy.
  • Can use TestProject actions in our test classes.

Let's start by finding out how we can download a TestProject addon proxy.

This blog post is the seventh part of my TestProject tutorial that is sponsored by TestProject.io. However, the views and opinions expressed in this tutorial are mine.

This blog post assumes that:

By the way, you might want to read the other parts of my TestProject tutorial.

Downloading a TestProject Addon Proxy

If we want to use use a custom addon found from the TestProject addon store, we have to download an addon proxy jar file. An addon proxy is a component that allows us to invoke the actual actions provided by a TestProject addon.

When an addon proxy is invoked by the TestProject SDK, the TestProject SDK communicates with the Agent API of the app.testproject.io website and downloads the invoked action (if the action hasn't been downloaded earlier). After the TestProject SDK has downloaded the invoked action, it runs the action in a separate process.

We can download a TestProject addon proxy from the app.testproject.io website by following these steps:

First, we have to choose the addon which we want to use. The app.testproject.io website has an addon store that allows us to download our private addons and addons shared by the other members of the TestProject community. This store has also a search function which provides us an easy way to find addons which are not listed on the main page of the addon store.

After we have found an addon we want to use, we have to open the download dialog by clicking the element that displays the basic information of the addon.

The following figure illustrates the layout of the 'Addons' page (the main page of the addon store):

However, because we want to use the custom addon which we wrote in the previous parts of my TestProject tutorial, we have to open the 'My Addons' page and open the download dialog of our custom addon (Blog Search Addon).

The following figure illustrates the layout of the 'My Addons' page:

Second, we have to download the addon proxy jar file by clicking the 'Proxy' link found from the 'Downloads' section of the modal dialog.

The following figure illustrates this step:

The name of the downloaded jar file is: Blog Search Addon.proxy.jar. Because I am not a huge fan of file names that contain spaces, I renamed this file to: blog.search.addon.proxy.jar.

We have now downloaded the jar file that contains our addon proxy. Next, we will find out how we can add our addon proxy to the classpath.

Adding the Downloaded Addon Proxy to the Classpath

Before we can use the actions found from the downloaded jar file, we have to add the jar file to our classpath. We can do this by following these steps:

First, we have to copy the jar file (blog.search.addon.proxy.jar) to the libs directory that is found from the root directory of our Gradle project. After we have copied our jar file to the libs directory, its content should look as follows:

libs
|__ blog.search.addon.proxy.jar
|__ io.testproject.sdk.java.jar

Second, because we will write code that uses the classes found from the blog.search.addon.proxy.jar file, we have to add this jar file to the compile dependency configuration. After we have made the required changes to our build.gradle file, its dependencies block looks as follows:

dependencies {
    compile files('libs/blog.search.addon.proxy.jar')
    tpsdk files('libs/io.testproject.sdk.java.jar')
}

We have now added our addon proxy jar to our classpath. Let's move on and find out how we can write tests which use custom TestProject actions.

Writing Test Classes Which Use TestProject Actions

Let's write these two test cases for the search function of my blog:

  • We have to ensure that the search result page has the expected title.
  • We have to verify that the search result page displays at least one search result.
By the way, I know that the second test is not a good test because it doesn't ensure that the search result page displays X result results. However, I use this example here because I don't want that this test fails in future when I publish more blog posts.

Before we can write our classes, we have to figure out how we can write code that runs TestProject actions. Next, we will find out how we can write this code.

Running TestProject Actions

We can run a TestProject action by invoking the executeProxy() method of the WebTestHelper class. When we use this method, we have to know these three things:

  • It takes the invoked action (an ActionProxy object) as a method parameter.
  • It returns a value of the ExecutionResult enum. The return value of the executeProxy() method specifies the result of the invoked action (ExecutionResult.PASSED or ExecutionResult.FAILED).
  • It can throw a checked expection (an Exception object).

In other words, when we invoke the execute() method, we have to write error handler code which ensures that:

  • Our test fails if the execute() method returns ExecutionResult.FAILED.
  • Our test fails if the execute() method throws an exception.

The problem is that we cannot take care of these things in our test classes because we don't want to add duplicate code to our test suite. That's why we have to create a utility class that can run TestProject actions and handle errors caused the invoked actions.

We can write this utility class by following these steps:

First, we have to create a package private class called ActionRunner. After we have created this class, its source code looks as follows:

class ActionRunner {

}

Second, we have to add a final WebTestHelper field to the ActionRunner class and implement a constructor that sets the value of the WebTestHelper field by using constructor injection. After we have implemented our constructor, the source code of the ActionRunner class looks as follows:

import io.testproject.java.sdk.v2.tests.helpers.WebTestHelper;

class ActionRunner {

    private final WebTestHelper webTestHelper;

    ActionRunner(WebTestHelper webTestHelper) {
        this.webTestHelper = webTestHelper;
    }
}

Third, we have to add a private private runAction() method to the ActionRunner class. This method takes an ActionProxy object as a method parameter, and it can throw a FailureException. After we have added this method to the ActionRunner class, we have to implement it by following these steps:

  1. Run the TestProject action.
  2. If the invoked action returned ExecutionResult.FAILED, throw a FailureException that fails our test.
  3. If the invoked action threw an Exception, throw a FailureException that fails our test.

After we implemented the runAction() method, the source code of the ActionRunner class looks as follows:

 
import io.testproject.java.sdk.v2.addons.proxy.ActionProxy;
import io.testproject.java.sdk.v2.enums.ExecutionResult;
import io.testproject.java.sdk.v2.exceptions.FailureException;
import io.testproject.java.sdk.v2.tests.helpers.WebTestHelper;

class ActionRunner {

    private final WebTestHelper webTestHelper;

    ActionRunner(WebTestHelper webTestHelper) {
        this.webTestHelper = webTestHelper;
    }

    void runAction(ActionProxy proxy) throws FailureException {
        try {
            ExecutionResult result = webTestHelper.executeProxy(proxy);
            if (result == ExecutionResult.FAILED) {
                throw new FailureException(String.format(
                        "The invocation of the action proxy: %s failed ",
                        proxy.getDescriptor().getClassName()
                ));
            }
        } 
        catch (Exception e) {
            throw new FailureException(e.getMessage(), e);
        }
    }
}
I use the default visibility here because my test classes are in the same package as my utility class. If this isn't the case in your situation, you should use the public access level modifier.

We are now ready to write our test classes. Let's move on and find how we can ensure that the search result page has the expected title.

Test 1: The Search Result Page Has the Expected Title

When we want to ensure that the search result page has the expected title, we have to write our test class by following these steps:

First, we have to create a new test class and configure the name and description of our test case. After we have created a new test class, its source code looks as follows:

import io.testproject.java.annotations.v2.Test;
import io.testproject.java.sdk.v2.tests.WebTest;

@Test(
        name = "The search result page must have the expected title",
        description = "Verify that the search result page has the expected title"
)
public class BlogSearchResultTitleTest implements WebTest {
    
}

Second, we have to add three input parameters to our test class:

  • The searchPageUrl specifies the URL of the page that displays the search form.
  • The searchTerm defines the used search term.
  • The expectedSearchResultPageTitle specifies the expected title of the search result page.

After we have added these input parameters to our test class, its source code looks as follows:

import io.testproject.java.annotations.v2.Parameter;
import io.testproject.java.annotations.v2.Test;
import io.testproject.java.sdk.v2.tests.WebTest;

@Test(
        name = "The search result page must have the expected title",
        description = "Verify that the search result page has the expected title"
)
public class BlogSearchResultTitleTest implements WebTest {

    @Parameter(description = "Contains the url of the search page")
    private String searchPageUrl;

    @Parameter(description = "Contains the submitted search term")
    private String searchTerm;

    @Parameter(description = "Contains the expected title of the search result page")
    private String expectedSearchResultPageTitle;
}

Third, we have to implement the execute() method of the WebTest interface by following these steps:

  1. Open the search page.
  2. Clear the search field by using the ClearBlogSearchFieldAction class which we created in an earlier part of this tutorial.
  3. Submit the search form by using the BlogSearchAction class which we created in an earlier part of this tutorial.
  4. Ensure that the search result page has the expected title.

After we have implemented the execute() method of the WebTest interface, the source code of our test class looks as follows:

import io.testproject.java.annotations.v2.Parameter;
import io.testproject.java.annotations.v2.Test;
import io.testproject.java.sdk.v2.drivers.WebDriver;
import io.testproject.java.sdk.v2.enums.ExecutionResult;
import io.testproject.java.sdk.v2.exceptions.FailureException;
import io.testproject.java.sdk.v2.tests.WebTest;
import io.testproject.java.sdk.v2.tests.helpers.WebTestHelper;
import io.testproject.proxy.addon.BlogSearchAddon;
import io.testproject.proxy.addon.net.petrikainulainen.testproject.addon.BlogSearchAction;
import io.testproject.proxy.addon.net.petrikainulainen.testproject.addon.ClearBlogSearchFieldAction;

@Test(
        name = "The search result page must have the expected title",
        description = "Verify that the search result page has the expected title"
)
public class BlogSearchResultTitleTest implements WebTest {

    @Parameter(description = "Contains the url of the search page")
    private String searchPageUrl;

    @Parameter(description = "Contains the submitted search term")
    private String searchTerm;

    @Parameter(description = "Contains the expected title of the search result page")
    private String expectedSearchResultPageTitle;

    @Override
    public ExecutionResult execute(WebTestHelper webTestHelper) 
            throws FailureException {
        
        WebDriver browser = webTestHelper.getDriver();
        browser.get(searchPageUrl);

        ActionRunner actionRunner = new ActionRunner(webTestHelper);

        ClearBlogSearchFieldAction clearSearchField = BlogSearchAddon
                .getClearBlogSearchFieldAction();
        actionRunner.runAction(clearSearchField);

        BlogSearchAction blogSearch = BlogSearchAddon.blogSearchAction(searchTerm);
        actionRunner.runAction(blogSearch);

        return browser.getTitle().equals(expectedSearchResultPageTitle)
                ? ExecutionResult.PASSED
                : ExecutionResult.FAILED;
    }
}
A TestProject addon jar has a class called: [AddonName]Addon. This class provides factory methods which allow us to create the invoked actions (ActionProxy objects). As we can see, in our case, the name of this class is: BlogSearchAddon.

We have now written a test class which ensures that the search result page has the expected title. Next, we will write a test class which verifies that the search result page displays at least one search result.

Test 2: The Search Result Page Displays at Least One Search Result

When we want to ensure that the search result page displays at least one search result, we have to write our test class by following these steps:

First, we have to create a new test class and configure the name and description of our test case. After we have created a new test class, its source code looks as follows:

import io.testproject.java.annotations.v2.Test;
import io.testproject.java.sdk.v2.tests.WebTest;

@Test(
        name = "The search result page must display at least one search result",
        description = "Verify that the search result page displays at least one search result"
)
public class BlogSearchResultCountTest implements WebTest {
    
}

Second, we have to add two input parameters to our test class:

  • The searchPageUrl specifies the URL of the page that displays the search form.
  • The searchTerm defines the used search term.

After we have added these input parameters to our test class, its source code looks as follows:

import io.testproject.java.annotations.v2.Parameter;
import io.testproject.java.annotations.v2.Test;
import io.testproject.java.sdk.v2.tests.WebTest;

@Test(
        name = "The search result page must display at least one search result",
        description = "Verify that the search result page displays at least one search result"
)
public class BlogSearchResultCountTest implements WebTest {

    @Parameter(description = "Contains the url of the search page")
    private String searchPageUrl;

    @Parameter(description = "Contains the submitted search term")
    private String searchTerm;
}

Third, we have to implement the execute() method of the WebTest interface by following these steps:

  1. Open the search page.
  2. Clear the search field by using the ClearBlogSearchFieldAction class which we created in an earlier part of this tutorial.
  3. Submit the search form by using the BlogSearchAction class which we created in an earlier part of this tutorial.
  4. Extract the number of search results from the search result page by using the BlogSearchResultFinderAction class which we created in an earlier part of this tutorial.
  5. Ensure that the search result page displays at least one search result.

After we have implemented the execute() method of the WebTest interface, the source code of our test class looks as follows:

import io.testproject.java.annotations.v2.Parameter;
import io.testproject.java.annotations.v2.Test;
import io.testproject.java.sdk.v2.drivers.WebDriver;
import io.testproject.java.sdk.v2.enums.ExecutionResult;
import io.testproject.java.sdk.v2.exceptions.FailureException;
import io.testproject.java.sdk.v2.tests.WebTest;
import io.testproject.java.sdk.v2.tests.helpers.WebTestHelper;
import io.testproject.proxy.addon.BlogSearchAddon;
import io.testproject.proxy.addon.net.petrikainulainen.testproject.addon.BlogSearchAction;
import io.testproject.proxy.addon.net.petrikainulainen.testproject.addon.BlogSearchResultFinderAction;
import io.testproject.proxy.addon.net.petrikainulainen.testproject.addon.ClearBlogSearchFieldAction;

@Test(
        name = "The search result page must display at least one search result",
        description = "Verify that the search result page displays at least one search result"
)
public class BlogSearchResultCountTest implements WebTest {

    @Parameter(description = "Contains the url of the search page")
    private String searchPageUrl;

    @Parameter(description = "Contains the submitted search term")
    private String searchTerm;

    @Override
    public ExecutionResult execute(WebTestHelper webTestHelper) 
            throws FailureException {
        
        WebDriver browser = webTestHelper.getDriver();
        browser.get(searchPageUrl);

        ActionRunner actionRunner = new ActionRunner(webTestHelper);

        ClearBlogSearchFieldAction clearSearchField = BlogSearchAddon
                .getClearBlogSearchFieldAction();
        actionRunner.runAction(clearSearchField);

        BlogSearchAction blogSearch = BlogSearchAddon.blogSearchAction(searchTerm);
        actionRunner.runAction(blogSearch);

        BlogSearchResultFinderAction searchResults = BlogSearchAddon
                .getBlogSearchResultFinderAction();
        actionRunner.runAction(searchResults);

        return searchResults.actualSearchResultCount > 0 
                ? ExecutionResult.PASSED 
                : ExecutionResult.FAILED;
    }
}
If you want to know how you can run these tests, you should read this blog post.

We have now written two test cases which demonstrate how we can use TestProject actions in our test classes. Let's summarize what we learned from this blog post.

Summary

This blog post has taught us six things:

  • If we want to use use a custom addon found from the TestProject addon store, we have to download an addon proxy jar file.
  • An addon proxy is a component that allows us to invoke the actual actions provided by a TestProject addon.
  • If we want to use an addon in our test classes, we have to add the downloaded addon proxy jar file to the compile dependency configuration.
  • We can run a TestProject action by invoking the executeProxy() method of the WebTestHelper class.
  • If we don't want to add duplicate error handling code to our test suite, we have to create a utility class that can run TestProject actions and handle errors caused the invoked actions.
  • We should create the invoked ActionProxy objects by using the factory methods provided by the [AddonName]Addon class.

P.S. You can get the example application of this blog post from Github.

1 comment… add one

Leave a Reply