12.1 Expression Rule Testing, Assertions & Test Cases
Key Takeaways
Native assertions check error-free evaluation, an expected output, or a user-defined Boolean expression.
test!output is available in custom assertion expressions for targeted checks.
Test exact boundaries and result types as well as normal values.
Package inspection does not itself establish that expression-rule tests passed; execute and review the appropriate test suite.
Expression Rule Testing and Assertions
A rule that works for one manually entered value may still fail on empty data, threshold values, or a changed dependency. Saved expression-rule test cases make expected behavior repeatable. They are especially important for Associate Developer topics such as interpreting rule output, building reusable expressions, and maintaining quality after an edit.
Begin with a precise contract: input types, permitted values, output type, and business meaning. A discount rule might accept a nonnegative amount and return a decimal discount. A query rule might return a DataSubset rather than a raw list. Without that contract, a passing assertion can validate the wrong behavior.
Ad Hoc Tests and Saved Cases
In the expression-rule editor, supply literal or expression values for rule inputs and run an ad hoc test. Inspect the returned type and shape, not just its displayed text. A scalar number, a single-item list, and a map containing a number are different outputs.
When the example captures a meaningful scenario, save it as a test case with a descriptive name. Define its input values and assertion. Run the saved cases again after changing the rule or a dependency. Saved test definitions are useful documentation; old results are not proof that the current rule still works. Appian does not persist test results with the rule on save.
The Three Supported Assertion Choices
The supported choices are successful evaluation, matching an expected output, and a Boolean assertion expression. There is no native assertion choice named Output throws an error in this test-case configuration.
| Assertion | What a pass establishes | Limitation |
|---|---|---|
| Expression evaluates without errors | The supplied scenario evaluates successfully | A wrong result can still pass |
| Output matches asserted output | Output type and value match the expectation | Entire complex values may be cumbersome to specify |
| User-defined expression evaluates to true | A targeted property or condition is satisfied | A weak condition can miss important defects |
For a rule returning 25, use expected output 25 when that is the contract. For a map with a dynamic timestamp and a required status, use an assertion such as test!output.status = "READY". test!output is provided in the assertion context; it is not a general variable available in the rule body.
Prefer focused assertions that explain the intended behavior. A test checking only that output is nonnull will not catch an incorrect total. A single very broad assertion combining many conditions can be harder to diagnose than several named cases. Choose checks that expose the error you actually need to prevent.
A Fully Defined Calculation Example
Suppose an original training rule returns zero for null or negative input and otherwise applies a ten-percent discount when the amount is at least 100. It rounds the discount to two decimal places:
if(
a!isNullOrEmpty(ri!amount),
0,
if(
ri!amount < 0,
0,
if(ri!amount >= 100, round(ri!amount * 0.10, 2), 0)
)
)
This is a teaching policy, not an Appian product default. Configure the rule input as Number (Decimal), then save these cases:
| Case | Input amount | Expected numeric output | Reason |
|---|---|---|---|
| Null amount | null | 0 | Defined invalid-input handling |
| Negative amount | -1 | 0 | Prevents a negative discount |
| Below threshold | 99 | 0 | Does not qualify |
| Exact threshold | 100 | 10 | Inclusive threshold |
| Above threshold | 125 | 12.5 | Correct percentage calculation |
The threshold cases distinguish >= from >. The above-threshold case distinguishes multiplying by 0.10 from subtracting 10. When using strict expected-output matching, confirm the numeric type as well as its value in the editor. If the public contract demands a particular type, test that explicitly.
Test Collections and Complex Results
For a rule processing a list, test an empty list, one item, several items, and any permitted null item. Check order, count, and data shape. If one item produces a list while another produces a map, the combined output may have an unexpected nested structure.
For queries, test no matches and authorized versus unauthorized users in the relevant environment. Do not assume a query test is independent of mutable source data. Separate pure calculations from data retrieval when possible, so calculations can be tested with supplied examples rather than live rows that may change tomorrow.
A clock-dependent rule needs an intentional time strategy. Passing an explicit reference date into a reusable calculation can produce stable tests for birthdays, leap years, or due dates. Relative expressions can help in other scenarios, but replacing every fixed date with today is not a universal solution: it can make expected results drift.
Bulk Execution and Release Gates
Appian supports running expression-rule tests in bulk through its automated-testing capabilities. Use the supported application/system execution tools or testing smart services for the environment. Review the resulting report and investigate failures before release. Do not assume package inspection automatically executes all tests or refuses every deployment with a failing assertion.
A test can fail because the output differs from the assertion, because the rule returns an error, or because an input or assertion expression cannot evaluate. These require different repairs. First reproduce the case, then inspect its inputs, current rule definition, and dependent objects.
Interfaces, Decisions, and Processes
Expression-rule assertions complement other testing methods. Exercise interfaces with actual interactions and caller mappings; a rendered preview is not an automated proof of every save. Decisions have their own test experience for input combinations and output. Process models need debugging of paths, assignments, data flow, and smart-service effects.
Treat an intentionally thrown error as an observed error outcome and test its contract through an appropriate harness or redesign the business validation as an explicit result. Do not invent an assertion option to make that error appear as a native passing test.
Takeaway: A useful test names the scenario, fixes the inputs, and checks the intended output contract. Re-run it after changes and use the appropriate testing method for each design object.
Sources checked 2026-10-18: expression-rule assertions and results and expression-rule testing.
Which assertion should verify that a discount rule returns exactly 10 for an amount of 100?
Test output matches the asserted output
Output throws an error
Any output is nonnull regardless of value
The package was inspected
A developer changes a shared calculation used by many expression rules. What provides useful regression evidence?
Only inspecting an export package
Running the relevant saved expression-rule tests in bulk and reviewing their results
Renaming all dependent rules
Opening the application without exercising any rule
An Expression Rule returns a complex Dictionary containing multiple fields, including a dynamically generated timestamp and a status code. The developer only needs to assert that the statusCode property equals "SUCCESS" without validating the dynamic timestamp. How should this assertion be configured?
Use 'Test output matches the asserted value' and enter null for the timestamp property
Use 'Output throws an error' and filter by the status code string
Use 'Expression evaluates to true' and write the expression: test!output.statusCode = "SUCCESS"
Use 'Test output matches the asserted value' and enable the Partial Dictionary Matching checkbox
Sections you finish are checked off in the contents.