What is Concurrency Testing in Software Testing?
โก Smart Summary
Concurrency testing detects defects that appear only when several users act on the same application at the same moment, exposing deadlocks, lost updates and locking problems that sequential functional checks never reveal.
What is Concurrency Testing?
Concurrency testing is a testing technique used to detect defects in an application when multiple users are logged in. In other words, it monitors the effect while multiple users perform the same action at the same time.
Concurrency testing is also referred to as multi-user testing. Testing a concurrent program is more challenging than testing a sequential program, because of non-determinism and synchronisation issues: the same test can pass on one run and fail on the next without a single line of code changing.
The diagram below illustrates the idea โ several users reach the same application resource in the same instant, and the test observes what the application does with the overlap.
Why Concurrency Testing
Two questions justify the effort, and both are invisible to single-user functional runs.
- It identifies the effects of accessing the same database records, modules or application code at the same time.
- It identifies and measures the level of deadlocking, locking, use of single-threaded code and constrained access to shared resources.
A feature can be fully correct for one user and still lose data for the second user who arrives a millisecond later, which is why this technique sits alongside performance testing rather than inside functional testing.
How to Perform Concurrency Testing
Concurrency testing follows a repeatable sequence. The steps below move from scoping to resolution.
- Step 1) Identify concurrency-prone flows. Look for shared state: simultaneous logins, seat or stock reservation, balance updates, batch jobs writing the same table and any single-threaded component in the path.
- Step 2) Set a concurrency target. Decide how many users must act at the same instant, drawn from real usage peaks rather than a round number.
- Step 3) Design the test cases. Each test case pairs the shared resource, the competing actions and the expected end state โ for example, two sessions withdrawing from one account must not both succeed.
- Step 4) Script and select the tool. A load generator that spawns configurable virtual users is required; JMeter is the common open-source choice, and its thread-group settings map directly onto concurrency scenarios.
- Step 5) Ramp incrementally. Increase concurrent users in stages instead of jumping to the target, so the level at which contention starts is visible.
- Step 6) Monitor and analyse. Watch lock waits, response-time spread, error rates and database blocking together โ a concurrency defect often shows as a timing anomaly before it shows as an error.
- Step 7) Resolve and re-run. Fix the synchronisation, indexing or locking cause, then repeat the same run to confirm the behaviour changed rather than moved.
Common Concurrency Defects
Concurrency defects fall into a small number of recognisable classes, and naming the class correctly usually points straight at the fix.
| Defect | What happens | Typical symptom |
| Race condition | The result depends on which session finished first | Correct totals on some runs, wrong on others |
| Deadlock | Two sessions each hold a lock the other needs | Transactions hang instead of returning an error |
| Lost update | A second write overwrites the first without reading it | A saved change silently disappears |
| Data corruption | A shared structure is written only partially | Records in a state no valid transaction could create |
| Starvation | One session never obtains the resource it waits for | A single user path times out while the system looks healthy |
Because these failures are intermittent, every run needs logs and timestamps captured; otherwise the defect cannot be raised credibly through the defect management process.
Concurrency Testing Example
Consider an online store holding the last unit of a product in stock. Two shoppers open the item at the same second and both press Buy.
- Scenario: Two sessions read stock = 1, both pass the availability check, and both write stock = 0.
- Expected result: One order is confirmed, the other receives an out-of-stock message, and stock never goes negative.
- Defect indicator: Both orders confirm, or stock lands at -1, which shows the availability check and the decrement are not executed as one atomic step.
- Variations worth running: The same two sessions editing one profile record, two approvals of the same request, and a batch job updating the table while a user saves.
The same pattern generalises: find one resource, two writers and no ordering guarantee. Running the scenario during system testing, before load is added, keeps the diagnosis clean.
Advantages of Concurrency Testing
- It relatively reduces the amount of effort needed to test an application by restricting the scope of concurrent interactions to a few widely used, well-tested components.
- Encapsulation allows the behaviour of a portion of a program to be analysed without reviewing the entire code base.
- It helps improve the reliability and robustness of concurrent programs.
- It exposes locking and blocking limits early, so capacity decisions rest on measured contention rather than on estimates.
Disadvantages of Concurrency Testing
The disadvantages below are typically encountered by testers while performing concurrency testing.
- The application needs to be tested on multiple platforms.
- Concurrency scenarios require more intensive tests than sequential ones.
- Functions do not return their result to the caller immediately; instead the result can be delivered later through notifications, blocks, callback functions or similar mechanisms, which makes testing more difficult.
- The information or program flow is not reflected in the call stack.
- The number of execution paths in the system can be extremely large, since the processes in a concurrent system interact with each other while they are executing.
- Concurrent programs have a higher ratio of failure than sequential ones.
- Debugging concurrent programs is difficult, because attaching a debugger changes the timing that caused the failure.

