This blog post describes how we can write tests for web applications by using the TestProject framework. After we have finished this blog post, we:
- Can write tests for web applications with TestProject framework.
- Understand how we can use Selenium API in our test classes.
- Know how we can pass input parameters to our test cases.
Let's start by writing our first test class.
This blog post assumes that:
By the way, you might want to read the other parts of my TestProject tutorial.
Writing Our First Test Class
When we write tests with TestProject framework, we have to follow these rules:
- We must put our test classes to the src/main/java directory. We must put our test class to this directory because we have to package our tests to a jar file and publish our tests (upload the jar file) on the app.testproject.io website before we can run them.
- We should describe the name and description of our test case (aka test class) by using the
@Test
annotation that is provided by the TestProject SDK. When we use this annotation, the app.testproject.io website uses the provided values in its test reports. - Because we are writing tests for a web application, our test classes must implement the
WebTest
interface provided by the TestProject SDK. - We can write a test case by implementing the
execute()
method of theWebTest
interface. Our implementation must return a value of theExecutionResult
enum that specifies the outcome of our test case.
Next, we will write a test which ensures that my website has the correct title. We can write this test by following these steps:
First, we have to create a new test class that implements the WebTest
interface. After we have created this class, its source code looks as follows:
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; public class WebSiteShouldDisplayExpectedTitleTest implements WebTest { @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { } }
Second, we have to configure the name and description of our test case. We can do this by annotating our test class with the @Test
annotation.
After we have configured the name and description of our test case, the source code of our test class looks as follows:
import io.testproject.java.annotations.v2.Test; 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; @Test( name = "My website should display the expected title", description = "Verify that my website displays the correct title" ) public class WebSiteShouldDisplayExpectedTitleTest implements WebTest { @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { } }
First, the description of this test case is not very useful because I wanted to avoid horizontal scrolling. Remember that you should always use a description that doesn't just repeat the name of your test case.
Second, we should always specify the name and description of our test case by using the @Test
annotation. Because the app.testproject.io website uses this information in its test reports, this approach helps us to locate the problem if a test case fails. If a test case fails, and it doesn't follow this rule, we have to read its source code before we know what the problem is. This is a waste of time.
Third, we have to implement the execute()
method by following these steps:
- Get a reference to the
WebDriver
object which controls the web browser that runs our test. - Ensure that the used web browser opens my website.
- Determine the return value of the
execute()
method. If my website has the correct title, we must returnExecutionResult.PASSED
. On the other hand, if my website doesn't have the expected title, we must returnExecutionResult.FAILED
.
After we have written our test case, the source code of our test class looks as follows:
import io.testproject.java.annotations.v2.Test; import io.testproject.java.sdk.v2.enums.ExecutionResult; import io.testproject.java.sdk.v2.drivers.WebDriver; 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; @Test( name = "My website should display the expected title", description = "Verify that my website displays the correct title" ) public class WebSiteShouldDisplayExpectedTitleTest implements WebTest { @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { WebDriver browser = webTestHelper.getDriver(); browser.get("https://www.petrikainulainen.net"); return browser.getTitle() .equals("Petri Kainulainen — Developing Software With Passion") ? ExecutionResult.PASSED : ExecutionResult.FAILED; } }
First, we will use the WebDriver
class provided by the TestProject SDK because it provides additional exception handling capabilities. However, if you don't want to use these features, you can also use the standard WebDriver
interface provided by the Selenium API. Also, keep in mind that the WebDriver
class provided by the TestProject SDK implements the "standard" Selenium API.
Second, because we are writing tests for web applications, our tests will use the Selenium API. This means that it's a good idea to follow Selenium best practices. Unfortunately, this is a quite broad topic and it's impossible to cover it in this blog post. However, we can get started by reading these articles:
- Bad coding practices for test automation with Selenium WebDriver
- Selenium Documentation: Test Design Considerations
- PageObject by Martin Fowler
Third, when we determine the return value of the execute()
method, we should use one of the these two values of the ExecutionResult
enum:
FAILED
means that our test case failed.PASSED
means that our test case passed.
We can now write simple tests for web applications by using the TestProject framework. However, sometimes we want to pass input parameters to our test case. Next, we will find out how we can do it.
Passing Input Parameters to Our Test Case
When we want to pass an input parameter to our test case, we have to follow these steps:
- Add a
private
field to our test class and ensure that the field can storeString
objects. - Annotate our new field with the
@TestParameter
annotation. When we do this, we can set the default value of our input parameter by setting the value of the@TestParameter
annotation'sdefaultValue
attribute.
Let's write a test case which ensure that a website has the expected title. We can write this test case by following these steps:
First, we have create a new test class and ensure that our test class implements the WebTest
interface. After we have created this test class, its source code looks as follows:
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; public class ParameterizedWebSiteShouldDisplayExpectedTitleTest implements WebTest { @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { } }
Second, we have to configure two input parameters:
- The
expectedTitle
parameter contains the expected title of the opened website. The default value of this parameter is: 'Petri Kainulainen — Developing Software With Passion'. - The
url
parameter contains the url of the opened website. The default value of this parameter: 'https://www.petrikainulainen.net'.
After we have configured these input parameters, the source code of our test class looks as follows:
import io.testproject.java.annotations.v2.TestParameter; 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; public class ParameterizedWebSiteShouldDisplayExpectedTitleTest implements WebTest { @TestParameter( defaultValue = "Petri Kainulainen — Developing Software With Passion" ) public String expectedTitle; @TestParameter(defaultValue = "https://www.petrikainulainen.net") public String url; @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { } }
Third, we have to configure the name and description of our test case. When our test case has input parameters, we can add the parameter values to the description of our test case by using the format: {parameterValue}
.
After we have configured the name and description of our test case, the source code of our test class looks as follows:
import io.testproject.java.annotations.v2.Test; import io.testproject.java.annotations.v2.TestParameter; 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; @Test( name = "The opened website should display the expected title", description = "The website: {url} should display the title: {expectedTitle}" ) public class ParameterizedWebSiteShouldDisplayExpectedTitleTest implements WebTest { @TestParameter( defaultValue = "Petri Kainulainen — Developing Software With Passion" ) public String expectedTitle; @TestParameter(defaultValue = "https://www.petrikainulainen.net") public String url; @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { } }
Fourth, we have to implement the execute()
method of the WebTest
interface and ensure that the opened website has the correct title. After we have written this method, the source code of our test class looks as follows:
import io.testproject.java.annotations.v2.Test; import io.testproject.java.annotations.v2.TestParameter; 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; @Test( name = "The opened website should display the expected title", description = "The website: {url} should display the title: {expectedTitle}" ) public class ParameterizedWebSiteShouldDisplayExpectedTitleTest implements WebTest { @TestParameter( defaultValue = "Petri Kainulainen — Developing Software With Passion" ) public String expectedTitle; @TestParameter(defaultValue = "https://www.petrikainulainen.net") public String url; @Override public ExecutionResult execute(WebTestHelper webTestHelper) throws FailureException { WebDriver browser = webTestHelper.getDriver(); browser.get(url); return browser.getTitle().equals(expectedTitle) ? ExecutionResult.PASSED : ExecutionResult.FAILED; } }
@TestParameter
annotation's description
attribute. Note that the value of this attribute is visible on the app.testproject.io website. To be more specific, the description of our input parameter is shown on the view that allows us to override the default parameter values of the invoked test cases.
We can now configure the input parameters that must be provided before we can run our tests by using the TestProject agent. We will talk more about this when we learn to run our test cases.
Let's summarize what we learned from this blog post.
Summary
This blog post has taught us five things:
- We must put our test classes to the src/main/java directory.
- We should specify the name and description of our test case by using the
@Test
annotation. - If we write tests for a web application, a test class must implement the
WebTest
interface provided by the TestProject SDK. - We can get a reference to the
WebDriver
object by using thegetDriver()
method of theWebTestHelper
class. - We can pass input parameters to a test case by using the
@TestParameter
annotation.
P.S. You can get the example application of this blog post from Github.