Power Your Software Testing with AI Agents and Cloud
The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering. Test Intelligently and Ship Faster.
- TestMu AI (Formerly LambdaTest)
- /
- Blog
- /
- Aggregate Model-Based Testing With Action-State Testing
Aggregate Model-Based Testing With Action-State Testing
Aggregate model-based testing merges stateless and stateful models. Action-state testing builds the model, covers requirements, and reveals missing actions.
Last Updated on:
Aggregate model-based testing covers stateless, stateful, and mixed test steps with one modeling technique instead of forcing a choice between two models. Action-state testing is currently the only aggregate method, introduced in the book Paradigm Shift in Software Testing and implemented in the Harmony tool, where every step pairs a user action, a system response, and the inner test state. This guide covers where you can use action-state testing and whether an LLM can build or traverse an action-state model.
Key Takeaways
- Action-state testing is the only aggregate model-based testing method, and it covers stateless, stateful, and mixed test steps through modeling rather than coding.
- An action-state step is a triple of a user action, a system response, and the inner test state, written as plain text instead of code.
- Action-state models use implementation-independent wording, so a team can build and validate the model against the specification before the code exists.
- A new state belongs in an action-state model when the same action makes the system calculate its response in a different way.
- Generating a statechart from an action-state model exposes missing actions, which expanded the shopping cart example from 5 requirement-covering test cases to 13.
- An LLM traversal of a graph model reached 96.3% edge coverage in a 2026 evaluation while the GraphWalker generator reached 100%, so a deterministic generator should stay the coverage authority.
Where can we use Action-state testing?
Action-state testing can be used for both stateful and stateless cases or even a mixed solution is possible if a long test case consists of inner states at some test steps, but at some other steps don't.
The 'action-state' model is textual, containing 'action-state' steps. Test cases are generated from the action-state model. An action-state step is a triple containing
- a (user) action,
- a (system) response,
- the inner (test) state.
Actions and responses must be implementation-independent and as abstract as possible. Action is described at a high level so that humans can understand. For example, an action can be as:
add items so that price remains below 10This is more abstract than adding two more concrete actions:
- add item for 7
- add item for 2
Even more concrete actions would be:
- click on the '+' icon next to Pizza Mexicana
- click on the '+' icon next to Coke
However, these are implementation-dependent actions and can be created when the implementation is ready. Making an implementation-independent model is a huge advantage as it can be done before coding and the team can validate it against the specification detecting almost all the problems in it.
Modeling is easy: a subsequent step (step 2) is executed immediately after a step (step 1) if step 2 is indented to the right:
step 1
step 2
If two steps' indentation is the same then they will be executed in different test cases:
step A
step B.
step A may contain an action and a response (stateless step):
action A => response A
or may contain a triple involving the inner state:
action A => response A STATE state for A
Models can be easily mapped with the requirements:
R1 my requirement A:
action A => response A STATE state for A
One model can embed other models. In this way, very complex systems can also be modeled.
You can easily build a model related to a feature or user story. From this model, the tool can generate the statechart and the test cases immediately. The statechart is another model representation, see later. By applying statecharts, you can easily detect missing actions and states. On the other hand, a statechart contains less information. The information on whether a transition is traversed more times is missing. For example, entering the wrong PIN for the first and second time is modeled in this way:
Add wrong PIN => wrong PIN added STATE waiting for PIN
Add wrong PIN => wrong PIN added STATE waiting for PIN
The related statecharts are the same independently of only once or twice the wrong PIN was added. Action-state models contain more information than statecharts and this is the reason why this technique doesn't need guard conditions and consequently coding.
However, to avoid coding the models are a little bit larger.
You can also set an appropriate test selection criterion. A tool can offer the missing action-state steps to satisfy the criterion. There may be steps to be offered that are invalid. Fortunately, you can easily recognize an invalid step and it can be rejected. Accepting or rejecting an offered step is the replacement of adding guard conditions and some other coding. It's much easier and non-coder testers can also do it.
Let's consider the same requirements as in my previous blog:

The most difficult part is how to find appropriate states. A reasonable solution is that if two actions are the same, but the system calculates the response in different ways, then we arrived at different states. Here is an example. The initial state is 'No discount, no bike'. From here we can add a car for which we go back to the initial state as no discount happens. Adding a second car, the calculation is the same as a car added to the cart. However, when ad the third car, the calculation will be different as a bike is also added for free. Thus we arrived at a new state 'Discount, bike added '. If we start with adding a bike and then adding three cars in a row, then there is another different calculation as the bike becomes free. Thus this is a new state: 'Discount, bike converted '. It's obvious that different calculations can be tested as any may contain an error. In this way, you can select a minimum number of test states.
Adding a bike at the same level as the first car, we go to another state 'No discount bike included'. All these steps cover requirement R1. This means that covering a single requirement with a single test is usually not enough. Here is the first version of the model:
INITIAL STATE No discount, no bike
R1 The customer can add cars or bikes one by one:
add car => one car STATE No discount, no bike
add car => two cars STATE No discount, no bike
add bike => bike added STATE No discount bike included
and the related statechart:

You can see that the statechart doesn't show that we added two cars. For covering requirement R2, we should delete a car/bike that should be a child step of a parent step where at least one car/bike is available:
INITIAL STATE No discount, no bike
R1 The customer can add cars or bikes one by one:
add car => one car STATE No discount, no bike
add car => two cars STATE No discount, no bike
R2 The customer can remove cars or bikes one by one:
delete car => one car STATE No discount, no bike
add bike => one bike STATE No discount bike included
R2 The customer can remove cars or bikes one by one:
delete bike => cart empty STATE No discount, no bike
To cover R3a, we should add two cars to the single bike:
add bike => one bike STATE No discount bike included
R3a discount for EUR 700 when bike converted free:
add two cars => two cars and a bike STATE Discount, bike converted
R3b can be covered if we add a third car:
add car => two cars STATE No discount, no bike
R3b For discount a bike is added when only cars are in the cart:
add car => three cars and a bike STATE Discount, bike added
Now it's reasonable to continue with R4. To cover it we remove the third car:
add car => three cars and a bike STATE Discount, bike added
R4 going below the discount limit it is withdrawn:
delete car => two cars STATE No discount, no bike
Considering R3c, we should add the deleted car again:
delete car => two cars STATE No discount, no bike
R3c reaching the limit again, previous discount back:
add car => three cars and a bike STATE Discount, bike added
Our last requirement is R3d. We cover it by deleting the second car, adding a bike, and adding the second car again:
delete car => two cars STATE No discount, no bike
R3d reaching the limit again adding a bike before:
delete car => one car STATE No discount, no bike
add bike => one car and a bike STATE No discount bike included
add car => two cars and a bike STATE Discount, bike converted
The whole model is the following:
INITIAL STATE No discount, no bike
R1 The customer can add cars or bikes one by one: (1)
add car => one car STATE No discount, no bike
add car => two cars STATE No discount, no bike
(2) R3b For discount a bike is added when only cars are in the cart:
add car => three cars and a bike STATE Discount, bike added
(3) R4 going below the discount limit it is withdrawn:
delete car => two cars STATE No discount, no bike
(4) R3c reaching the limit again, previous discount back:
add car => three cars and a bike STATE Discount, bike added
(5) R3d reaching the limit again adding a bike before:
delete car => one car STATE No discount, no bike
add bike => one car and a bike STATE No discount bike included
add car => two cars and a bike STATE Discount, bike converted
(6) R2 The customer can remove cars or bikes one by one:
delete car => one car STATE No discount, no bike
add bike => one bike STATE No discount bike included
(7) R3a discount for EUR 700 when bike converted free:
add two cars => two cars and a bike STATE Discount, bike converted
(6) R2 The customer can remove cars or bikes one by one:
delete bike => cart empty STATE No discount, no bike
We covered the requirements with only five test cases (the ones (1) - (5)). Are we ready? Let's see. The related statechart is here:

It's a great help as missing actions can be detected easily. For example, from the state 'Discount, bike added' we can delete or add a bike. Considering 'No discount bike included', there is a missing edge going to itself, when deleting a bike from two. We can also add bike going to itself and going to 'Discount, bike converted'. Finally, considering 'Discount, bike converted', there are several missing actions, i.e., adding/deleting a car and adding/deleting a bike to itself, delete bike going to 'No discount no bike' and delete car/bike going to 'No discount bike included'.
Traversing each valid action/edge is the minimum test selection criterion, thus covering only the requirements is clearly insufficient. Involving the missing actions, we get the following improved model:
INITIAL STATE No discount, no bike
R1 The customer can add cars or bikes one by one:
add car => one car STATE No discount, no bike
add car => two cars STATE No discount, no bike
R3b For discount a bike is added when only cars are in the cart:
add car => three cars and a bike STATE Discount, bike added
add bike => three cars and two bikes STATE Discount, bike added
delete bike => three cars STATE No discount, no bike
R4 going below the discount limit it is withdrawn:
delete car => two cars STATE No discount, no bike
R3c reaching the limit again, previous discount back:
add car => three cars and a bike STATE Discount, bike added
R3d reaching the limit again adding a bike before:
delete car => one car STATE No discount, no bike
add bike => one car and a bike STATE No discount bike included
add car => two cars and a bike STATE Discount, bike converted
R2 The customer can remove cars or bikes one by one:
delete car => one car STATE No discount, no bike
add bike => one bike STATE No discount bike included
add bike => two bikes STATE No discount bike included
add five bikes => seven bikes STATE Discount, bike converted
add bike => eight bikes STATE Discount, bike converted
delete bike => seven bikes STATE Discount, bike converted
delete bike => six bikes STATE No discount bike included
delete bike => one bike STATE No discount bike included
R3a discount for EUR 700 when bike converted free:
add two cars => two cars and a bike STATE Discount, bike converted
delete car => one car and a bike STATE No discount bike included
add car => three cars and a bike STATE Discount, bike converted
delete car => two cars and a bike STATE Discount, bike converted
delete bike => two cars STATE No discount, no bike
add bike => two cars and two bikes STATE Discount, bike converted
R2 The customer can remove cars or bikes one by one:
delete bike => cart empty STATE No discount, no bike
delete bike => cart empty STATE No discount, no bike
The number of test cases increased from 5 to 13. The new statechart is the following:

Now all the actions are involved. We have seven requirements and we carefully covered by 13 test cases. You may think 13 tests are too many, but it depends on the software risk analysis. If the risk is high, you should test it carefully, otherwise tricky bugs remain undetected. You cannot merge cars and bikes as vehicles as they behave differently, only bikes are added freely or converted for free, and cars are not.
Considering the statechart, if you simply traverse it, some invalid tests are generated. For example, adding a bike from the initial state, then adding five bikes we arrive at 'Discount, bike converted'. However, having only six bikes we have no discount, a contradiction. The state action-state model consists of only valid steps.
As mentioned, by applying a stronger test selection criterion, new steps are offered. For example, when applying all-transition-pairs criterion the following step is offered:

This is because the edge/action pair (add car, add bike), where add car is the action starts from and arrives at the initial state hasn't been covered. If the risk is very high you should add these steps as well.
Abstract steps become executable tests through a mapping layer. Each action, such as "add car", maps to one function or method in the page object model of the automation code, and each response maps to one assertion. The model stays implementation-independent, so a UI change edits the mapped function and leaves the model untouched. The same action-state model can therefore drive a manual run, a browser test, and API testing without being rewritten.
Keep the model in version control next to the test code and regenerate the test cases in your pipeline. A requirement change then edits one action-state step, and regeneration only touches the test cases that pass through that step. Reviewers read the model diff in the pull request instead of rereading every generated test case, and requirement labels such as R3b stay attached to the tests that cover them.
Key Takeaway: Action-state testing fits stateless, stateful, and mixed systems, and the statechart generated from an action-state model reveals the missing actions that requirement coverage alone leaves untested.
Can an LLM build or traverse an action-state model?
An LLM can traverse an existing action-state model and shorten the generated paths, but it cannot be trusted to author the model or to certify coverage. The two jobs are different. Building the model means reading the requirements and deciding where a new state begins. Traversing the model is mechanical path selection over a graph.
An empirical evaluation published in August 2026 measured that split. The authors ran five models, GPT-5.1, GPT-5.2, Claude Opus 4.5, Claude Sonnet 4.5 and Gemini 2.5 Pro, against GraphWalker, an open source MIT-licensed path generator, on four graph models, from a 10 vertex traffic light controller to a 129 vertex web application. Their LLM4MBT pipeline averaged 100% vertex coverage and 96.3% edge coverage in about 300 test steps. GraphWalker's quick random generator reached 100% edge coverage in 524 steps. The paths were shorter, and a small share of edges went untraversed.
For action-state testing the untraversed edges matter more than the step count. The statechart is what exposes missing actions, such as the delete bike edge that returns to the same state, so a traversal that stops short of full edge coverage removes the check this method depends on. The same paper reports that one prompt can produce different paths across runs, and that the five models were not equally reliable, one failing on the RISC-V graph. Keep a deterministic generator as the coverage authority. GraphWalker accepts edge coverage, vertex coverage and requirement coverage as stop conditions and replays a run from a seed, so the coverage number stays reproducible.
The useful place for an assistant is the offered-step loop above. You set the test selection criterion, the tool offers the missing steps, and a model can draft the action and response wording in implementation-independent language. You still accept or reject each offered step, and that judgement is the part no generator replaces.
Key Takeaway: An LLM can traverse an existing action-state model and produce shorter paths, but authoring the model and certifying edge coverage still need a human reviewer and a deterministic generator such as GraphWalker.
Conclusion
Action-state testing is an aggregate MBT method. This is the only one that requires no coding at all, just modeling. The model can be converted to a statechart, by which the original model can be improved and made complete. It can be widely used, and tricky bugs can be detected. From the models, abstract test cases are generated that can be manually executed. The model consists of implementation-independent steps, thus it's a true shift left testing method for MBT.
Author
István Forgács, PhD is a software testing and test design automation expert with 30+ years of experience in test automation, model-based testing, and agile testing methodologies. He is the CEO and co-founder of 4Test-Plus and the creator of Harmony, a two-phase model-based test design automation tool focused on improving test maintainability and reducing testing costs. István has led EU- and Hungary-funded research projects, headed software testing groups, and researched core algorithms for testing tools and analyzers. He is the co-author of four books, including Modern Software Testing Techniques and Agile Testing Foundations, and actively contributes to advancing test design methods such as action state testing and general predicate testing through education, tools, and community platforms.
Aggregate Model-Based Testing FAQs
Did you find this page helpful?
More Related Blogs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance
- Advanced access controls
- Advanced data retention rules
- Advanced Local Testing
- Premium Support options
- Early access to beta features
- Private Slack Channel
- Unlimited Manual Accessibility DevTools Tests



