How to Scale Automated API Tests: Speed Up, Reduce Boilerplate, and Boost Stability

This article shares practical techniques for writing and maintaining large numbers of automated API test cases in a Java Spring/Dubbo environment, covering faster execution by limiting service initialization, a three‑step test structure, data‑provider and factory optimizations, resource cleanup strategies, and stability improvements for CI pipelines.

Youzan Coder
Youzan Coder
Youzan Coder
How to Scale Automated API Tests: Speed Up, Reduce Boilerplate, and Boost Stability

Introduction

When new engineers join a company, they are usually taught how to write a single automated test case from configuration to assertion and execution. In real projects, however, teams often need to create and manage hundreds or thousands of API test cases that run continuously in CI, which introduces new challenges beyond merely running a single case.

Execution Efficiency

The test framework is built on Spring and targets Dubbo services. Initializing a service consumer involves three steps: listening to the registry, connecting to the provider, and creating a client proxy. Because each test class inherits a common base that initializes all services, running a test for service A also initializes unused services B, C, etc., causing a typical case to take ~30 seconds (only ~1 second of actual logic).

Solution: Initialize only the services required for the current test case to eliminate unnecessary overhead.

Test Case Writing and Maintenance

Example Scenario

A merchant creates a membership card for a shop, then updates it. The test must cover creation, update, verification, and cleanup.

Step 1: Prepare data objects for creating and updating the card.

Step 2: Execute the create operation.

Step 3: Execute the update operation.

Step 4: Verify the update result.

Step 5: Clean up the created card.

Below is the original Java test code (kept unchanged for reference):

@Test
public void testUpdate() {
try {
/* create new and update card objects */
CardCreateDescriptionDTO descCreate = new CardCreateDescriptionDTO();
descCreate.setName(xxxx); // ... other setters omitted
CardUpdateDescriptionDTO descUpdate = new CardUpdateDescriptionDTO();
descUpdate.setName(xxxxx); // ... other setters omitted
/* create card */
String cardAlias = cardService.create((int)kdtId, descCreate, operator).getCardAlias();
/* update card */
cardService.update(kdtId, cardAlias, descUpdate, operator);
/* verify result */
CardDTO cardDTO = cardService.getByCardAlias(cardAlias);
Assert.assertEquals(cardDTO.getName(), xxxx, "会员卡更新失败");
} catch (Exception e) {
Assert.assertNull(e);
} finally {
// cleanup omitted for brevity
}
}

While this works, the boilerplate quickly becomes unwieldy when extending to more complex scenarios.

Three‑Part Test Structure

To simplify, split each test into three logical parts:

Data preparation

Operation execution

Result verification

Data Preparation Optimizations

Use TestNG @DataProvider to reuse execution logic with different parameters. A CardFactory generates test objects, reducing repetitive setter calls. Two factory methods illustrate different granularity:

public CardCreateDescriptionDTO genRuleCreate(Boolean isPost, Integer discount, Long rate, Long pointsDef, ... )
public CardCreateDescriptionDTO genRuleSimpleCreate(String name)

Pre‑creating required data (pre‑set data) can improve stability, speed, and isolation. Mark data with meaningful variable names (e.g., queryCardUid = DataMocker.MOCK_YZUID.get(1)) and separate read‑only resources from those used for write verification.

Resource Cleanup

Collect identifiers of created cards in a global list recycleCardAlias. After each test (e.g., in @AfterMethod), iterate over the list and delete the cards, then clear the list. This “garbage‑bin” approach offers flexible cleanup timing compared to immediate deletion.

@AfterMethod
public void tearDownMethod() {
    for (int i = 0; i < recycleCardAlias.size(); ++i) {
        try {
            deleteCard(kdtId, recycleCardAlias.get(i), cardOperatorDTO);
        } catch (Exception e) {
            logger.error("clear card fail: " + recycleCardAlias.get(i));
        }
    }
    recycleCardAlias.clear();
}

Method Encapsulation

Encapsulate repetitive actions (e.g., createCard(), getCard(), deleteCard()) and verification logic (e.g., checkUpdateCardResult(...)) to keep test methods focused on the business scenario.

Stability Practices

Reduce external dependencies; use pre‑generated data instead of calling other services.

Prefer pre‑set data over on‑the‑fly creation to lower failure rates.

Isolate tests with different accounts to prevent cross‑contamination.

Adjust timeouts for test environments that are slower than production.

Apply defensive programming: verify data existence and clean up stale data before each run.

Identify flaky tests by increasing threadPoolSize and invocationCount in TestNG to reproduce and fix intermittent failures.

Conclusion

The article presents three practical improvements for large‑scale automated API testing in a Java Spring/Dubbo stack: trimming service initialization to speed up execution, restructuring test cases into a concise three‑step pattern to reduce boilerplate, and employing data‑provider, factory, pre‑set data, and systematic cleanup to enhance stability and maintainability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentAutomated TestingDubboCITestNG
Youzan Coder
Written by

Youzan Coder

Official Youzan tech channel, delivering technical insights and occasional daily updates from the Youzan tech team.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.