Cucumber - JDBC Integration

Cucumber: JDBC Integration Explained

JDBC (Java Database Connectivity) integration with Cucumber enables you to perform automated database testing by directly connecting to a database and executing queries. This approach is ideal for validating data, schema, and database operations while adhering to behavior-driven development (BDD) principles.

Why Use JDBC with Cucumber?

Combining JDBC with Cucumber provides the following advantages:

  • Direct interaction with the database for querying and validation.
  • Business-readable test scenarios using Gherkin syntax.
  • Supports testing CRUD operations, stored procedures, and triggers.
  • Validates backend operations triggered by application workflows.

Setting Up Cucumber for JDBC Integration

1. Project Setup:

Add the necessary dependencies to your Maven or Gradle project, including Cucumber and the required JDBC driver (e.g., MySQL, PostgreSQL):


                  <dependency>
                    <groupId>io.cucumber</groupId>
                    <artifactId>cucumber-java</artifactId>
                    <version>X.X.X</version>
                  </dependency>
                  <dependency>
                    <groupId>io.cucumber</groupId>
                    <artifactId>cucumber-junit</artifactId>
                    <version>X.X.X</version>
                  </dependency>
                  <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>X.X.X</version>
                  </dependency>
                

2. Define Feature Files:

Write feature files to define database-related scenarios in Gherkin syntax. For example, validating a user record in the database:


                  Feature: Validate User in Database
              
                  Scenario: Verify user details after registration
                    Given a user with username "testuser" registers in the application
                    When the registration is successful
                    Then the database should have a user with username "testuser"
                

3. Step Definitions:

Implement step definitions using JDBC to connect to the database and perform queries:


                  import java.sql.Connection;
                  import java.sql.DriverManager;
                  import java.sql.ResultSet;
                  import java.sql.Statement;
                  import static org.junit.Assert.*;
              
                  public class JdbcStepDefinitions {
              
                      private Connection connection;
              
                      @Given("a user with username {string} registers in the application")
                      public void registerUser(String username) {
                          System.out.println("User registration logic with username: " + username);
                      }
              
                      @When("the registration is successful")
                      public void registrationSuccess() {
                          System.out.println("Registration is confirmed.");
                      }
              
                      @Then("the database should have a user with username {string}")
                      public void verifyUserInDatabase(String username) throws Exception {
                          String url = "jdbc:mysql://localhost:3306/testdb";
                          String user = "root";
                          String password = "password";
                          connection = DriverManager.getConnection(url, user, password);
              
                          Statement statement = connection.createStatement();
                          ResultSet resultSet = statement.executeQuery("SELECT * FROM users WHERE username = '" + username + "'");
              
                          boolean userExists = resultSet.next();
                          assertTrue("User should be present in the database", userExists);
              
                          connection.close();
                      }
                  }
                

4. Run the Tests:

Create a test runner class to execute your scenarios using @RunWith(Cucumber.class):


                  import org.junit.runner.RunWith;
                  import io.cucumber.junit.Cucumber;
                  import io.cucumber.junit.CucumberOptions;
              
                  @RunWith(Cucumber.class)
                  @CucumberOptions(features = "src/test/resources/features", glue = "stepdefinitions")
                  public class JdbcTestRunner {
                  }
                

Real-World Scenario:

Consider a banking application where a money transfer operation updates account balances. You can validate the database reflects the expected balances after the transaction.

Feature File:

                  Scenario: Validate account balances after money transfer
                    Given a user transfers $100 from account "A123" to account "B456"
                    When the transfer is successful
                    Then the database should show account "A123" with balance $900
                    And the database should show account "B456" with balance $1100
                
Step Definitions:

                  @Given("a user transfers \$\{int} from account {string} to account {string}")
                  public void transferMoney(int amount, String fromAccount, String toAccount) {
                      System.out.println("Money transfer logic for accounts: " + fromAccount + " and " + toAccount);
                  }
              
                  @Then("the database should show account {string} with balance \$\{int}")
                  public void verifyAccountBalance(String account, int expectedBalance) throws Exception {
                      Statement statement = connection.createStatement();
                      ResultSet resultSet = statement.executeQuery("SELECT balance FROM accounts WHERE account_number = '" + account + "'");
              
                      if (resultSet.next()) {
                          int actualBalance = resultSet.getInt("balance");
                          assertEquals("Account balance mismatch", expectedBalance, actualBalance);
                      } else {
                          fail("Account not found in the database");
                      }
                  }
                

Best Practices

  • Use parameterized queries to avoid SQL injection.
  • Leverage connection pooling for better performance.
  • Isolate test environments with dedicated test databases.
  • Clean up test data after test execution to maintain consistency.