The Challenge: Testing Workflows in Production-Like Conditions
Workflows are unique in that they involve human participants in approval chains. You can't test them perfectly in sandbox because humans don't cooperate. A test approver might not check their inbox for 3 days, breaking your SLA simulation. A test participant might reject when your test expects approval. And you can't test them in production because workflows involve real people making real business decisions.
The result is a testing gap. You can validate individual workflow components (Groovy scripts, notification templates) but you can't fully simulate end-to-end workflow execution with realistic human behavior until you go live. This is why advance planning, careful design, and defensive coding matter so much.
Testing Strategy: Four-Tier Approach
Tier 1: Unit Test Groovy Scripts in Isolation
Groovy scripts are the most error-prone part of workflows. Test them outside the workflow context using a JUnit or similar test framework. Create test data (mock participant objects, mock plan objects) and call the script, verifying the output.
Example: Unit test for assignee rule script
import org.junit.Test
import static org.junit.Assert.*
class ApprovalAssigneeTest {
@Test
void testDirectManagerAssignment() {
def participant = [
id: "P123",
manager: [id: "M456"],
manager.manager: [id: "D789"]
]
def approver = assignApprover(participant)
assertEquals("M456", approver)
}
@Test
void testFallbackToDirector() {
def participant = [
id: "P123",
manager: null, // No manager
manager.manager: [id: "D789"]
]
def approver = assignApprover(participant)
assertEquals("D789", approver)
}
@Test
void testFallbackToCompensationTeam() {
def participant = [
id: "P123",
manager: null,
manager.manager: null
]
def approver = assignApprover(participant)
assertEquals("compensation-team@company.com", approver)
}
}
Tier 2: Sandbox Test with Test Participants and Test Approvers
Create a sandbox environment with test participants who have complete hierarchy data (manager, director, VP). Create test approvers with valid email addresses and sandbox user accounts. Submit test plans/disputes/quotas that trigger your workflows. Manually check:
- Does the workflow fire? Check the workflow instance log.
- Does the correct approver receive the task? Check the test approver's inbox.
- Can the approver approve/reject? Can they add comments?
- Does the workflow advance to the next step on approval?
- Does it return to the initiator on rejection?
- Do notifications arrive with correct content?
- Do context variables populate correctly (participant name, plan name, etc.)?
Test Org Hierarchy (Example for Sandbox):
CEO (test-ceo@sandbox.company.com) ├── VP Sales (test-vp@sandbox.company.com) │ ├── Director West (test-dir-west@sandbox.company.com) │ │ ├── Manager 1 (test-mgr-1@sandbox.company.com) │ │ │ ├── Participant A (P1001) │ │ │ └── Participant B (P1002) │ │ └── Manager 2 (test-mgr-2@sandbox.company.com) │ │ └── Participant C (P1003) │ └── Director East (test-dir-east@sandbox.company.com) │ └── Manager 3 (test-mgr-3@sandbox.company.com) │ ├── Participant D (P1004) │ └── Participant E (P1005) └── Compensation Manager (test-comp-mgr@sandbox.company.com)
Use this shallow, manageable hierarchy for testing. Two levels below CEO is enough to test manager → director approval chains.
Tier 3: Edge Case Simulation
Test scenarios where real hierarchy data is messy:
- Missing manager: Create a participant with no manager assigned. Trigger the workflow. Verify fallback logic routes to the next level or compensation team.
- Circular reporting: Create a participant whose manager is also in the plan (participant is a manager of someone else). Trigger the workflow. Verify no circular approval.
- Terminated manager: Create a test approver with status="TERMINATED" and assign as someone's manager. Trigger the workflow. Verify escalation skips the terminated user.
- Out of office: Simulate an approver who doesn't respond within SLA. Set approval SLA to 1 day. Wait 1+ day. Verify escalation triggers (auto-approval, escalation to backup, etc.).
- Boundary conditions: Test with plan.annualValue = exactly the threshold ($500K). Test with quota achievement = exactly 100%, exactly 200%. Test with commission = zero or negative.
Tier 4: Manual Walkthrough of Approval Chains
Before go-live, sit with the business team and walk through the approval workflow manually. Get a test participant, a test manager, a test director, and a test VP in a room (or on a video call). Have the participant submit a test plan. The test manager approves. The test director approves. The test VP approves. Watch at each step whether the workflow behaves as expected. Document any surprises or deviations from spec.
Four Common Failure Modes and How to Debug Them
Failure Mode 1: Workflow Doesn't Fire
Symptom: You submit a plan, dispute, or quota update. The workflow should trigger, but nothing happens. No workflow instance is created. No approval task appears.
Root Causes:
- Workflow is not activated. The workflow definition exists but status = "INACTIVE". New instances are not created.
- Trigger event is wrong. The workflow is listening for plan.submitted but the actual event fired is plan.submitted_for_approval (a different event).
- Condition is too restrictive. The condition says "only trigger if plan.type = 'INCENTIVE'" but the test plan is type='ADMIN'. The condition evaluates to false and the workflow doesn't fire.
- Event is not being published. IM is configured incorrectly and isn't publishing the event to Advanced Workflow.
Debugging Steps:
- Check workflow definition status: Is it "ACTIVE"? If INACTIVE, activate it.
- Check trigger event name: Does it match the actual event being fired by IM?
- Check conditions: Run the condition Groovy script manually with test data. Does it return true? If false, the condition is filtering out your test case.
- Check IM event publishing: Is IM configured to publish the event to Advanced Workflow? Check IM settings and integration logs.
- Check Advanced Workflow logs: Is the event being received? Check the Advanced Workflow integration log for incoming events.
Example: Condition Filtering Out Test Cases
// Workflow condition plan.type == "INCENTIVE" && plan.status == "SUBMITTED" // Test case data plan = [type: "ADMIN", status: "SUBMITTED"] // Evaluation: false (plan.type is "ADMIN", not "INCENTIVE") // Result: Workflow doesn't fire (expected if you want to skip admin plans)
Failure Mode 2: Workflow Stuck Pending (Approver Not Found)
Symptom: Workflow fires and creates an instance. The first approval step is pending. The expected approver never receives a task. The workflow sits in this step indefinitely, waiting for an approver that doesn't exist.
Root Causes:
- Participant has no manager. Most common cause. participant.manager.id is null. Assignee rule tries to assign to null and fails.
- Manager ID doesn't exist in the system. The participant's manager field points to a manager ID that has no corresponding user.
- Manager is inactive. The manager account has been terminated or disabled.
- Assignee rule script throws an exception. The Groovy script has a bug (e.g., unguarded null pointer access) and returns null or throws an error.
Debugging Steps:
- Check the workflow instance log. Look for the step that's pending. Does it show an approver assignment? Or does it show a null approver?
- Check the participant's manager field in IM. Is it populated? Is it null?
- If manager field is populated, check if that manager has an active user account in the system.
- If manager exists, check the assignee rule script. Run it manually with the participant's data. Does it return a non-null approver ID?
- Check for Groovy exceptions in the workflow log. Is there a null pointer exception or other script error?
This is the most common production issue. A participant is missing a manager, the workflow fires, and nobody knows what to do. The workflow appears to be running but is actually stuck. This is discovered when an approval is overdue and the support team investigates.
Prevention: Pre-go-live Hierarchy Audit
Before go-live, run a data audit to identify all participants with missing managers:
// Identify participants with no manager SELECT participant_id, participant_name, manager_id FROM participants WHERE manager_id IS NULL AND status = 'ACTIVE' ORDER BY participant_name; // Expected output: empty result (or very few) // If result has > 5% of participants: Stop. Do not go live. Fix hierarchy first.
Failure Mode 3: Groovy Script Silent Failure
Symptom: A Groovy script step runs but produces wrong results. The workflow routes to the wrong approver, or a calculation produces the wrong value. No error message is logged. The workflow appears to succeed but delivers incorrect output.
Root Causes:
- Unguarded null pointer access. The script accesses participant.manager.manager.id but participant.manager is null. This throws a NullPointerException, the script fails silently, and the workflow continues with a null value.
- Logic error. The script has correct syntax but wrong business logic. Example: if (commission > 1000) instead of if (commission >= 1000).
- Variable scope issue. A variable is set inside an if block but accessed outside the block. The variable is null when accessed.
- API call failure not checked. The script calls an external API and the call fails, but the script doesn't check the response status and continues.
Debugging Steps:
- Enable detailed logging in the Groovy script using log.info() and log.error() calls.
- Check the workflow instance log for script output. Look for logged variables, decision points, and error messages.
- Run the script manually in a Groovy console with test data. Does it produce the expected output?
- Check for null values. If a variable should have a value but is null, backtrack to see where the null came from.
- Check API responses. If the script calls an API, log the response status and body.
Example: Script with Silent Failure
// BAD: Unguarded null pointer def approver = participant.manager.manager.id // If participant.manager is null, throws NullPointerException // GOOD: Null-safe navigation def approver = participant?.manager?.manager?.id // Returns null if any level is null // BEST: With fallback def approver = participant?.manager?.manager?.id ?: "compensation-team@company.com" // Returns null-safe value with fallback to compensation team
Failure Mode 4: Wrong Routing (Incorrect Approver Assigned)
Symptom: Workflow fires and routes to an approver, but it's the wrong approver. A participant's manager receives the task instead of the director, or a participant in region A receives a task meant for region B approvers.
Root Causes:
- Hierarchy data is incorrect. A participant's manager field is populated but points to the wrong person (data entry error when onboarding).
- Manager reassignment happened mid-workflow. A participant was reassigned to a new manager while their approval workflow was pending. The workflow uses the old manager data.
- Approver selection logic is flawed. The Groovy script has conditional logic that's correct for most cases but wrong for edge cases.
- Conditions misidentified the workflow type. A quota dispute should route to the regional analyst, but the condition didn't check region and it routed to the global analyst.
Debugging Steps:
- Check the workflow step that assigned the approver. What was the assignment rule?
- Check the participant's manager field at the time the workflow fired. Is it what you expected?
- Check if the participant's data changed during the workflow. If the manager field was updated, when did that happen?
- If the approver selection is Groovy-based, run the script manually with the participant's data from the time the workflow fired. Does it produce the wrong approver?
- Check if there's an alternate assignment rule. If the primary rule fails, is there a fallback?
Debugging Tools: How to Access Workflow Logs and Execution Traces
Workflow Instance Log
For any workflow instance, you can access a log showing which steps executed, when they executed, and what happened at each step. The log includes:
- Step name and type (approval, notification, Groovy, etc.).
- Step start and end time.
- Assigned approver (if approval step).
- Approver's response (Approve, Reject, etc.).
- Any errors or exceptions thrown.
- Logging output from Groovy scripts (if log.info() calls were used).
How to access: In Advanced Workflow UI, navigate to Instances → [instance ID] → View Log. The log is a detailed execution trace from workflow start to finish (or to the current pending step if the workflow is still running).
Step-Level Logging with log.info() and log.error()
In Groovy steps, use logging to output diagnostic information:
// Log key decision points
log.info("Evaluating approver for participant: " + participant.id)
log.info("Manager ID: " + participant?.manager?.id)
log.info("Plan value: " + plan?.annualValue)
if (plan?.annualValue >= 500000) {
log.info("High-value plan, routing to director")
return "DIRECTOR_APPROVAL"
} else {
log.info("Standard plan, routing to manager")
return "MANAGER_APPROVAL"
}
// Log exceptions
try {
def response = httpClient.post(url, headers, body)
log.info("API response status: " + response.status)
} catch (Exception e) {
log.error("API call failed: " + e.message)
log.error("Stack trace: " + e.stackTrace)
}
Workflow Execution Trace (Full Context)
For complex workflows with multiple steps and branches, the execution trace shows the full journey: which conditions were evaluated, which steps were executed, which transitions were taken. This helps you understand the "happy path" of a workflow and verify it matches your design.
Example trace:
Workflow Instance: WF_12345 (Plan Approval) Status: COMPLETED Started: 2026-04-12 09:00:00 UTC Completed: 2026-04-12 14:30:00 UTC Step 1: Manager Approval Status: COMPLETED Approver: manager@company.com Response: APPROVED Completed: 2026-04-12 09:15:00 Duration: 15 minutes Step 2: Value Check (Groovy) Status: COMPLETED Condition: plan.annualValue >= 500000 Result: TRUE (plan value = $750K) Transition: Go to Step 3 (Director Approval) Completed: 2026-04-12 09:16:00 Step 3: Director Approval Status: COMPLETED Approver: director@company.com Response: APPROVED Completed: 2026-04-12 14:25:00 Duration: 4 hours 9 minutes Step 4: Notification Status: COMPLETED Recipients: participant@company.com, manager@company.com Message: "Your plan has been approved" Completed: 2026-04-12 14:30:00 Outcome: APPROVED
Advanced Workflow Go-Live Checklist
Before activating workflows in production, verify the following 10 items:
| Item | Check | Pass/Fail |
|---|---|---|
| 1. Hierarchy Validation | Run the orphaned manager query. No more than 5% of active participants have missing managers. All manager IDs exist as active users in the system. | [ ] |
| 2. Null Approver Testing | In sandbox, create test cases where hierarchy is missing. Verify fallback logic routes to backup approver or compensation team. Workflow never hangs with null approver. | [ ] |
| 3. Escalation Path Testing | Verify SLA timers and escalation rules work. Set a 1-day SLA, wait 1+ day, confirm escalation triggers. Test auto-approval and escalation-to-backup scenarios. | [ ] |
| 4. Circular Reporting Testing | Create test scenario where participant.manager = another participant in the same plan. Verify no circular approval. Workflow routes to next level. | [ ] |
| 5. Notification Content Review | Check all notification templates. Verify context variables populate correctly (participant name, plan name, amounts). Check email addresses are not hardcoded. Verify personalisation logic works. | [ ] |
| 6. Groovy Script Error Handling | Code review all Groovy scripts. Verify null-safe navigation (?.). Verify try-catch blocks around API calls. Verify log statements for diagnostics. Unit test critical scripts. | [ ] |
| 7. API Integration Testing | If workflows call external APIs (payroll, CRM, etc.), test API calls in sandbox. Verify response handling. Test failure scenarios (API timeout, invalid response). Verify retry logic. | [ ] |
| 8. Automation Workflow Safety | For automation workflows (no human gate), confirm 100% sandbox validation before production activation. Test all edge cases. Have rollback plan. Never auto-activate multiple automation workflows simultaneously. | [ ] |
| 9. Activation Sequence | Activate workflows in correct order. Non-critical approval workflows first. Automation workflows last. If workflow A triggers workflow B, activate A before B. Test the chain in sandbox. | [ ] |
| 10. Documentation and Support Prep | Document each workflow (what it does, how it triggers, how to troubleshoot). Train support team on stuck approval procedures. Have on-call support for first 48 hours post-go-live. | [ ] |
Production Troubleshooting: What to Do When a Workflow Fails
When a workflow gets stuck or fails in production:
- Get context. Who reported the issue? Which participant, which plan/dispute? What step is the workflow stuck on?
- Check the workflow instance log. Look at the execution trace. Which step failed? Is there an error message?
- Classify the failure. Is it one of the four failure modes (doesn't fire, stuck pending, silent failure, wrong routing)? Or something else?
- Check data. Verify participant hierarchy, manager existence, data correctness. Is the issue a data problem or a workflow problem?
- If stuck pending: Manually escalate the approval to the next level (if possible via UI). Or contact the assigned approver to unblock.
- If silent failure: Run the Groovy script manually with the same input data. Reproduce the bug. Fix the script. Deploy a new workflow version.
- If wrong routing: Verify the participant's data at the time the workflow fired. If data is correct, review the routing logic. If data is wrong, fix the data (may require rerunning workflow).
- If multiple instances fail: Stop activating new workflows. Diagnose the root cause. Fix it. Retest. Only reactivate after confirmation.
Key Takeaways
- Testing workflows is uniquely challenging because humans are involved. Use a four-tier strategy: unit test scripts, sandbox test with realistic data, edge case simulation, manual walkthrough.
- The four most common failure modes are: (1) Workflow doesn't fire (check activation, trigger, condition), (2) Stuck pending (check hierarchy, approver null checks), (3) Silent Groovy failure (add logging, test scripts), (4) Wrong routing (check hierarchy data, verify conditions).
- The most common production issue is a participant with no manager. The workflow fires, can't find an approver, and hangs indefinitely. Prevent this with pre-go-live hierarchy audits.
- Use workflow logs and step-level logging (log.info(), log.error()) to debug failures. Always log decision points and error conditions in Groovy scripts.
- Pre-go-live checklist: validate hierarchy, test null approver handling, test escalation, test circular relationships, review notifications, error-handle Groovy, test APIs, validate automation workflows, plan activation sequence, prepare support team.
- Never activate automation workflows without 100% sandbox validation. They run at scale with no human gate. A bug affects everyone simultaneously.