top of page

Welcome
to NumpyNinja Blogs

NumpyNinja: Blogs. Demystifying Tech,

One Blog at a Time.
Millions of views. 

From Spreadsheets to Scenarios: Designing an Excel Reader for My First Cucumber BDD Project

It was the time when I started my DS algo project in March 2025.


When I started my first automation project using Cucumber BDD, one of the earliest challenges I faced was test data management. Hardcoding test values inside feature files or step definitions felt wrong and unscalable. I needed a clean, reusable, and flexible way to read test data — excel was the best choice to read test data.

This blog explains why I designed my Excel reader the way I did, based on real project requirements, and how this design fits well with Cucumber BDD.


The Problem I Needed to Solve

Before writing any code, I listed down my actual requirements.


My key requirements were:

  1. Single Excel file with multiple sheets

    • Each sheet represents a module or feature

    • Example: Login, Register, Queue, Graph etc.

  2. Column headers can vary

    • Not all sheets have the same columns

    • Some sheets may have test case id, Username, Password

    • Others may have Input code, Actual result, Expected result etc.

  3. Each sheet can have multiple rows

    • One sheet may have 10–20 test scenarios

    • All rows should be usable for test execution

  4. Cucumber-friendly data access

    • I wanted to access data using meaningful names, not column indexes

    • Example: data.get("Username") instead of getCell(1)

  5. Beginner-friendly but scalable

    • This was my first project, but I didn’t want to rewrite everything later.


Why I Chose List<Map<String, String>>

This was the most important design decision.


Why not arrays?

  • Arrays depend on column order → break easily


Why Map<String, String>

Because:

  • Key = Column Header

  • Value = Cell Data


This means:

data.get("Username");
data.get("Password");
data.get("ExpectedResult");

No matter where the column is placed, the test still works. And since each row is a separate test case, I wrapped it as:

List<Map<String, String>>
  • One map = one test scenario

  • One list = all scenarios in that sheet


Why I Read the Header Row First

Row headerRow = sheet.getRow(0);

The first row defines the meaning of every column.

By reading headers first:

  • I dynamically map column names

  • I don’t care if columns move left or right

  • Different sheets can have different headers

This design makes the user friendly for future reference.

 

Why I Loop Through All Rows

for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++)

Each row represents a separate test scenario. Instead of reading a single row:

  • I fetch all rows

  • Return them as a collection

  • Let the test framework decide how to execute them

This works perfectly with:

  • Cucumber scenario outlines

  • TestNG DataProviders

  • Sequential or parallel execution

 

Why I Included Empty Rows Safely

Row.MissingCellPolicy.CREATE_NULL_AS_BLANK

Excel files are rarely perfect:

  • Someone might leave a cell empty

  • Someone might add spacing or formatting

Instead of failing the test:

  • Empty cells return empty strings

  • Execution continues smoothly

This makes the framework robust and easy to use as a Beginner.

 

Why I Handle Different Cell Types

Excel cells are tricky:

  • Some are strings

  • Some are numbers

  • Some are Booleans

  • Some have formulas

That’s why I added a helper method:

private static String getCellValue(Cell cell)

This ensures:

  • All values are converted to strings

  • Tests don’t break due to cell type mismatch

  • Step definitions remain simple


Why I Used a Single Utility Class

ExcelReader.getAllRows("Login");

All Excel logic is:

  • Isolated

  • Reusable

  • Independent of test logic


This follows a core automation principle:

Test logic should never care how data is read.


If tomorrow I switch from Excel to JSON:

  • Only this class changes

  • Tests remain untouched


How This Fits Perfectly with Cucumber BDD

In Cucumber:

  • Feature files define behavior

  • Step definitions define actions

  • Excel defines test data


This ExcelReader acts as a bridge between business-readable tests and technical execution.

Example usage:

List<Map<String, String>> testData = ExcelReader.getAllRows("Login");

Each row can drive one scenario or one iteration.

 

Final Thoughts

This ExcelReader may look simple, but it solves real-world automation problems:

  • Multiple sheets

  • Dynamic headers

  • Scalable test data

  • Cucumber-friendly design

  • Beginner-safe implementation

Most importantly, it helped me focus on test behavior.


If you’re building your first automation framework, designing your data layer thoughtfully will save you months of refactoring later.

Recent Posts

See All

+1 (302) 200-8320

NumPy_Ninja_Logo (1).png

Numpy Ninja Inc. 8 The Grn Ste A Dover, DE 19901

© Copyright 2025 by Numpy Ninja Inc.

  • Twitter
  • LinkedIn
bottom of page