Turn your manual testers into automation experts Request a DemoStart testRigor Free

Spring Framework Testing

Spring Framework Testing

What is Spring Framework (Spring)?

Spring is a popular open-source framework in the Java community. Spring can be considered both an application framework and an Inversion of Control (IoC) container for the Java platform. At a high level, IoC means that the custom-written code receives the flow of control from the framework, as opposed to traditional programming. The primary purpose of doing this is to increase modularity and make the code extensible. Spring framework adopts the Enterprise JavaBeans programming model. Rod Johnson wrote the Spring Framework, with the initial release in October 2002, and the current stable version is 5.3.23. Spring has several inbuilt modules like Core, Data Access, Web, Integration, and Testing. These modules support various services.

Let's dive deep into the main testing types, namely:

The Spring framework has in-built modules that support Unit and Integration testing. We'll also discuss the best options for end-to-end testing.

Unit Testing

Unit testing is the process of testing individual units or components of a software system. It plays a major part in ensuring the software's quality. Unit testing support classes in the Spring Framework are divided into the following two categories:
  • General Testing Utilities: For general testing utilities, we use the org.springframework.test.util package. This package offers multiple general testing utilities that can be used in Unit and Integration testing. This package covers all the scenarios that arise while writing unit test classes.
  • Spring MVC Testing Utilities: For Spring MVC testing utilities, we use the org.springframework.test.web package that contains the ModelAndViewAssert method. This method can be used with JUnit to perform unit tests that incorporate the ModelAndView objects.
Below is a sample unit test code:
public class TestWebApp extends SpringBootHelloWorldTests {
  @Autowired
  private WebApplicationContext webApplicationContext;
  private MockMvc mockMvc;
  
  @Before
  public void setup() {
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
  }
  
  @Test
  public void validateBookDetails() throws Exception {
  mockMvc.perform(MockMvcRequestBuilders.get("/bookDetails"))
    .andExpect(status().isOk())
    .andExpect(content().contentType("application/json;charset=UTF-8"))
    .andExpect(jsonPath("$.name").value("Science Encyclopedia for Kids"))
    .andExpect(jsonPath("$.ISBN").value("190-122-45-901"))
    .andExpect(jsonPath("$.price").value(25));
  }
}

In this example, we are testing the validateBookDetails() method with a GET request. MockMvc.perform() accepts a MockMvcRequest and mocks the API call given the fields of the object. Here, we built a request via MockMvcRequestBuilders, specifying only the GET path and contentType property. For this call, we've set four assertions within the andExpect() methods: that the response returns a 200 (OK status code), the name field of the returned object equals "Science Encyclopedia for Kids", the ISBN field equals "190-122-45-901", and the price field equals 25.

Integration testing

Integration testing is the process of testing the interface between two software units or modules. It focuses on determining the correctness of the interface. It's crucial to perform integration testing without deploying to an application server or connecting to other enterprise infrastructure.

This kind of testing includes:
  • Correct Spring IoC container contexts wiring
  • Data access using JDBC or an ORM tool
Here is a sample integration test code:
@SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
class RegisterUseCaseIntegrationTest {
  
  @Autowired
  private MockMvc mockMvc;
  
  @Autowired
  private ObjectMapper objectMapper;
  
  @Autowired
  private UserRepository userRepository;

  @Test
  void registrationWorksThroughAllLayers() throws Exception {
    UserResource user = new UserResource("demotest", "demotest@galaxy.net");
    mockMvc.perform(post("/forums/{forumId}/register", 42L)
      .contentType("application/json")
      .param("sendWelcomeMail", "true")
      .content(objectMapper.writeValueAsString(user)))
      .andExpect(status().isOk());
    UserEntity userEntity = userRepository.findByName("demotest");
    assertThat(userEntity.getEmail()).isEqualTo("demotest@galaxy.net");
  }
}

The above example demonstrates a sample testing scenario that uses the @ExtendWith annotation to tell JUnit 5 to enable Spring support. Additionally, @AutoConfigureMockMvc is used to add a MockMvc instance to the application context. This MockMvc object is used to perform a POST request to the application and validate that it responds as expected. UserRepository from the application context is used to validate that the request has led to an expected change in the state of the database.

E2E Testing

End-to-End, or System testing, is performed to ensure that the entire application from start to end, along with integrated modules, dependencies, interfaces, and communication with other systems, is working as expected. It focuses on validating end-user interaction with the system.

Various approaches to perform E2E testing for Spring include:
  • Selenium with Spring Boot
  • Cypress with Spring Boot
  • testRigor

Selenium using Spring Boot

In the following example, Selenium with Spring Boot is used to perform E2E testing on a 'Sample WebTable', validating the table title and entering data into the second and third rows of the last column.

See sample test code below:
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HomePage implements BasePage{
  @Autowired
  private VisibilityHelper visibilityHelper;

  @FindBy(xpath = "//input[@id='result']")
  public WebElement sec_rw;

  @FindBy(xpath = "//section[@id='table1']/div[1]/div[1]/div[1]/div[1]/" +
  "table[1]/tbody[1]/tr[3]/td[4]/input[1]")
  public WebElement third_rw;

  @FindBy(xpath = "//h1[text()='Sample Table']")
  public WebElement table_hdr;

  public void assertTableData() {
    visibilityHelper.waitForVisibilityOf(table_hdr);
    visibilityHelper.waitForVisibilityOf(sec_rw);
    sec_rw.sendKeys("This is second row data");
    third_rw.sendKeys("This is third row data");
  }
}

Cypress with Spring Boot

Cypress is an end-to-end testing tool that enables developers and QA professionals to write and run tests against any web application. It's simple syntax, real-time reloading, and automatic waiting features make it an excellent choice for E2E testing, even with Spring Boot applications.

Consider a Spring Boot application with a simple form on the homepage that collects user name and email. Here's how you can write a Cypress test for it:
describe('Home Page Form Submission', function() {
  it('Submits user data', function() {
    // Visit the home page
    cy.visit('http://localhost:8080');
    
    // Find the input fields and type test data
    cy.get('input[name=name]').type('Test User');
    cy.get('input[name=email]').type('testuser@example.com');
    
    // Submit the form
    cy.get('form').submit();
    
    // Verify the success message
    cy.contains('Thank you for your submission, Test User!');
  });
});

In the script above, cy.visit() is used to load the homepage, cy.get().type() to find the form fields and enter test data, cy.get().submit() to submit the form, and cy.contains() to verify the success message.

testRigor

When it comes to end-to-end testing, it's hard to beat testRigor for its ease of use, rapid speed of test creation, and minimal maintenance. testRigor is a powerful cloud-hosted AI no-code automation tool with auto-heal capabilities, enabling the entire QA team (including manual testers) to create robust E2E tests quickly. Here are some of the benefits of using it for your testing needs:

  • Supports cross-platform and cross-browser testing without significant configuration steps.
  • Test creation is up to 15X faster than with other tools.
  • Test maintenance is practically eliminated and takes little to no time.
  • Provides support for 2FA testing for Gmail, text messages, and Google authenticator.
  • Easy integration with most CI/CD tools.
  • Facilitates easy mocking of API calls and accessing databases if needed.
  • Shared suite can be used to perform parallel testing of apps on both iOS and Android platforms. You can read more about the key features of testRigor here.
Here's a sample code to perform an E2E test on a 'Sample WebTable', validating the table title and entering data into the second and third rows of the last column. testRigor provides a very effective way of interacting with forms and tables. We can refer to cells in a table with the intersection of row and column, where the value for the row is the value of the first cell in the row, and the column is the value of the header/top cell in the column:
check that page contains "Sample Table"
click on the second button within the context of table at row containing "york1" and column "Action"
click on the second button within the context of table at row containing "spk2" and column "Action"
enter "This is second row" into table "actions" at row "102" and column "Additional Data"

Conclusion

Testing is an essential part of the software development lifecycle, particularly for complex frameworks like Spring. Ultimately, ensuring high-quality standards for software involves performing all levels of testing. This ensures that the application functions correctly at each level and as a whole, leading to robust and reliable software products.