Writing End-to-End Tests With Spock Framework – Configuration (Spring Boot Edition)

After we have finished this lesson, we:

  • Understand how we can start our Spring Boot application before our end-to-end tests are run.
  • Know how we can configure our end-to-end tests by using a custom test execution listener.
  • Can initialize our database into a known state before a feature method is run.

This lesson assumes that:

Important note: You must finish the lessons: Configuring Our End-to-End Tests - Spring Boot and Initializing Our Database With the @Sql Annotation before you continue this lesson. These lessons describe how you can start your Spring Boot application, create a custom TestExecutionListener that configures Selenium WebDriver, and iniatialize your database into a known state by using the @Sql annotation.

Because I don’t want to repeat myself, this lesson doesn’t provide a comprehensive description of these techniques. The goal of this lesson is to simply demonstrate how you can use these techniques when you are writing end-to-end tests with Spock framework.

Configuring Our End-to-End Tests

We can configure our end-to-end tests by following these steps:

First, we have to create a new specification class and ensure that its feature methods are run when we run our end-to-end tests. After we have created a new specification class, its source code looks as follows:

1import org.junit.experimental.categories.Category
2import spock.lang.Specification
3
4@Category(EndToEndTest.class)
5class ExampleSpec extends Specification {
6
7}

Second, we have to load the application context of our Spring Boot application. After we have done this, the source code of our specification class looks as follows:

1import org.junit.experimental.categories.Category
2import org.springframework.boot.test.context.SpringBootTest
3import spock.lang.Specification
4
5@SpringBootTest(classes = TaskTrackerApplication.class)
6@Category(EndToEndTest.class)
7class ExampleSpec extends Specification {
8
9}

Third, we have to ensure that our Spring Boot application is started when its application context is loaded. Also, we must remember to specify the port that is listened by the started Spring Boot application. Because our example uses the default port (8080), we don’t have to make any other changes to our configuration.

After we have made the required changes to our specification class, its source code looks as follows:

 1import org.junit.experimental.categories.Category
 2import org.springframework.boot.test.context.SpringBootTest
 3import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
 4import spock.lang.Specification
 5
 6@SpringBootTest(classes = TaskTrackerApplication.class,
 7        webEnvironment = WebEnvironment.DEFINED_PORT
 8)
 9@Category(EndToEndTest.class)
10class ExampleSpec extends Specification {
11
12}

Fourth, we have to specify the Spring profile that is used when the feature methods of our specification class are run (endToEndTest). After we have done this, the source code of our specification class looks as follows:

 1import org.junit.experimental.categories.Category
 2import org.springframework.boot.test.context.SpringBootTest
 3import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
 4import org.springframework.test.context.ActiveProfiles
 5import spock.lang.Specification
 6
 7@SpringBootTest(classes = TaskTrackerApplication.class,
 8        webEnvironment = WebEnvironment.DEFINED_PORT
 9)
10@ActiveProfiles(Profiles.END_TO_END_TEST)
11@Category(EndToEndTest.class)
12class ExampleSpec extends Specification {
13
14}

Fifth, we have to configure Selenium WebDriver by using the custom TestExecutionListener that we created in the lesson: Configuring Our End-to-End Tests - Spring Boot . We can do this by following these steps:

  1. Annotate our specification class with the @SeleniumTest annotation and ensure that the type of the created WebDriver object is ChromeDriver.
  2. Add a WebDriver field to our specification class and ensure that the created WebDriver object is injected into that field.

After we have configured Selenium WebDriver, the source code of our specification class looks as follows:

 1import org.junit.experimental.categories.Category
 2import org.openqa.selenium.WebDriver
 3import org.openqa.selenium.chrome.ChromeDriver
 4import org.springframework.beans.factory.annotation.Autowired
 5import org.springframework.boot.test.context.SpringBootTest
 6import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
 7import org.springframework.test.context.ActiveProfiles
 8import spock.lang.Specification
 9
10@SpringBootTest(classes = TaskTrackerApplication.class,
11        webEnvironment = WebEnvironment.DEFINED_PORT
12)
13@SeleniumTest(driver = ChromeDriver.class)
14@ActiveProfiles(Profiles.END_TO_END_TEST)
15@Category(EndToEndTest.class)
16class ExampleSpec extends Specification {
17
18    @Autowired
19    WebDriver browser
20}

Sixth, we have ensure that the existing data is deleted from the database after a feature method has been run. After we have made the required changes to our specification class, its source code looks as follows:

 1import org.junit.experimental.categories.Category
 2import org.openqa.selenium.WebDriver
 3import org.openqa.selenium.chrome.ChromeDriver
 4import org.springframework.beans.factory.annotation.Autowired
 5import org.springframework.boot.test.context.SpringBootTest
 6import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
 7import org.springframework.test.context.ActiveProfiles
 8import org.springframework.test.context.jdbc.Sql
 9import spock.lang.Specification
10
11import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD
12
13@SpringBootTest(classes = TaskTrackerApplication.class,
14        webEnvironment = WebEnvironment.DEFINED_PORT
15)
16@SeleniumTest(driver = ChromeDriver.class)
17@Sql(
18        value = 'classpath:/com/testwithspring/master/cleandb.sql',
19        executionPhase = AFTER_TEST_METHOD
20)
21@ActiveProfiles(Profiles.END_TO_END_TEST)
22@Category(EndToEndTest.class)
23class ExampleSpec extends Specification {
24
25    @Autowired
26    WebDriver browser
27}

Seventh, we have to initialize our database into a known state before a feature method is run. We can do this by following these steps:

  1. Insert the user data into our database.
  2. Insert the task data into our database.

After we have made the required changes to our specification class, its source code looks as follows:

 1import org.junit.experimental.categories.Category
 2import org.openqa.selenium.WebDriver
 3import org.openqa.selenium.chrome.ChromeDriver
 4import org.springframework.beans.factory.annotation.Autowired
 5import org.springframework.boot.test.context.SpringBootTest
 6import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
 7import org.springframework.test.context.ActiveProfiles
 8import org.springframework.test.context.jdbc.Sql
 9import spock.lang.Specification
10
11import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD
12
13@SpringBootTest(classes = TaskTrackerApplication.class,
14        webEnvironment = WebEnvironment.DEFINED_PORT
15)
16@SeleniumTest(driver = ChromeDriver.class)
17@Sql(value = [
18        'classpath:/com/testwithspring/master/users.sql',
19        'classpath:/com/testwithspring/master/tasks.sql'
20])
21@Sql(
22        value = 'classpath:/com/testwithspring/master/cleandb.sql',
23        executionPhase = AFTER_TEST_METHOD
24)
25@ActiveProfiles(Profiles.END_TO_END_TEST)
26@Category(EndToEndTest.class)
27class ExampleSpec extends Specification {
28
29    @Autowired
30    WebDriver browser
31}

We can now configure our end-to-end tests when we are using Spock Framework. Also, this configuration allows us to configure the state of the WebDriver object before a feature method is run and clear the state of the WebDriver object after a feature method has been run. For example, we can implement a setup() method that logs a user in and write a cleanup() method that logs the user out.

Let’s summarize what we learned from this lesson.

Summary

This lesson has taught us four things:

  • We can start our Spring Boot application by setting the value of the @SpringBootTest annotation’s webEnvironment attribute to WebEnvironment.DEFINED_PORT.
  • Our custom TestExecutionListener creates a new WebDriver object and injects the created object into a Spock specification.
  • We can initialize the state of the WebDriver object in the setup() method and clean its state in the cleanup() method.
  • We can initialize our database into a known state by annotating our specification class with the required @Sql annotations.

Get the source code from Github