Skip to content
Laksana Adi

Test Data Design for Subscription Renewal Flow · Backend / API

Designing a Test Data Matrix for Efficient Data-Driven Testing

When testing a system, we often need different data to cover different business scenarios. One common challenge is that we keep changing the same test data during test execution.

This can become inconvenient, especially when we need to run end-to-end tests repeatedly. The data can become difficult to track, and we may also spend more time preparing the test environment instead of actually testing the feature.

To avoid this, I prefer to design the test data upfront. Instead of constantly changing one account to match different scenarios, I prepare several accounts with specific data configurations. Each account represents a particular business scenario and can be reused across test executions.

This makes the test data more consistent, easier to manage, and easier to understand.

In this case, I applied this approach when testing a subscription renewal flow.

The Challenge

The feature has three types of plans:

There are also different outcomes during the renewal process. A Pro subscription can either be renewed automatically or downgraded to Basic, depending on the user's balance.

This means that testing the complete flow requires different combinations of subscription plans, payment cycles, and account balances.

If I used only one account, I would need to repeatedly change the account configuration between test scenarios. This makes the test execution slower and increases the chance of using incorrect test data.

The Approach: Test Data Matrix

To make the testing more consistent, I prepared five test accounts. Each account was configured with a specific combination of subscription and balance conditions.

AccountPlanPayment CycleBalanceExpected Result
Account ABasicSufficientNo invoice, remains Basic
Account BProMonthlySufficientInvoice generated → Auto renewal
Account CProMonthlyInsufficientInvoice generated → Auto downgrade
Account DProYearlySufficientInvoice generated → Auto renewal
Account EProYearlyInsufficientInvoice generated → Auto downgrade

The main idea is that each account represents a specific test scenario. Instead of modifying one account again and again, I can use these five accounts as a predefined test account pool.

End-to-End Test Flow

With the accounts prepared, the testing flow becomes much simpler.

The first step is to make sure all five accounts have the correct subscription data and expiration dates. Then, I trigger the renewal cron job that processes subscriptions 7 days before expiration.

The first thing to verify is the invoice generation. The expected result is:

After that, the flow continues based on the account balance.

For accounts with sufficient balance:

Invoice generated but not paid → Subscription expired but sufficient balance → Subscription auto renewed → Pro plan continues

For accounts with insufficient balance:

Invoice generated but not paid → Subscription expired but insufficient balance → Subscription ended → Downgrade to Basic plan

This allows me to test both positive and negative scenarios in the same execution.

Why Use Multiple Accounts?

The main benefit is not simply having more test accounts. The important part is that the accounts are pre-configured and mapped to specific test scenarios.

Without this approach, the testing process could look like this:

Change account to Basic → test → change to Pro Monthly → test → change balance → test → change to Pro Yearly → test → change balance again → test.

With a predefined test account pool, it becomes:

This makes the end-to-end testing easier to repeat, especially during regression testing.

Easier Tracking and Debugging

Another benefit is that each test scenario has its own isolated data.

For example, if the monthly renewal scenario fails, I can immediately focus on Account B or Account C without worrying about whether another test scenario has changed the same account's data.

This makes tracking and debugging easier because the test data is predictable and isolated. It also helps when investigating unexpected results. Instead of asking, "What happened to this account before the test?", I can refer to the predefined configuration for that specific account.

Easier Test Evidence

Having separate accounts also makes collecting and organizing testing evidence much easier. Each account can be treated as one test scenario, so the evidence can be grouped accordingly.

For example:

This makes the final test report easier to review because the evidence has a clear relationship with the test data and expected result.

It is also useful when someone needs to review or validate a specific scenario later. We can simply point to the corresponding account and its evidence instead of going through a large set of mixed screenshots or logs.

Test Coverage

The five accounts also give a simple way to visualize the coverage. We cover:

Instead of thinking about each test case separately, I can look at the test data matrix and quickly see which business scenario is already covered.

Conclusion

For this subscription renewal feature, I found that preparing a Test Data Matrix and a Pre-configured Test Account Pool makes end-to-end testing much more efficient.

The goal is not to create as many accounts as possible. The goal is to create a small number of accounts that represent the important business scenarios. In this case, five accounts are enough to cover the main subscription renewal paths without repeatedly changing the same account's data.

This approach also makes the test data more consistent and easier to maintain. More importantly, it helps with test execution, debugging, tracking, and evidence collection because each scenario has its own isolated data.

For me, this is a practical example of how data-driven testing can be applied to real QA work: prepare the right data once, map it to the expected scenarios, and make the actual test execution as simple as possible.