Introduction: The Hidden Gap in CRM Test Automation

Many teams have automated the actions that interact with Dynamics 365 CRM — creating records, triggering flows, updating data — but still rely on humans to validate the results. Someone logs into CRM, searches for the record, checks the fields, and confirms that everything looks right.

This manual step is slow, inconsistent, and undermines the value of automation.

In this post, we’ll close that gap by validating CRM data programmatically using the Dataverse Web API.

The Current State: Automated Actions, Manual Validation

A typical pattern looks like this:

  • An automated test triggers a Power Automate flow.
  • The flow creates a Contact or other Dataverse record.
  • The test receives a 200 OK response.
  • A human logs into CRM to confirm the data is correct.

The automation stops halfway. The system confirms the flow ran, but not that the data is correct.

The Goal: Closing the Loop with Automated CRM Validation

The next logical step is to automate the validation itself. We want to confirm:

  • The record exists.
  • The fields contain the expected values.
  • Related records were created.
  • Business rules, plugins, or flows executed correctly.

All without logging into the CRM UI.

Solution Overview: Validating Dynamics 365 Data via the Dataverse Web API

The Dataverse Web API gives you direct, secure access to CRM data. Using it, your automated tests can:

  • Query tables (entities)
  • Filter by field values
  • Expand related records
  • Assert business logic outcomes

This turns your test suite into a true end‑to‑end validation pipeline.

Architecture: How the End‑to‑End Test Flow Works

A simple architecture looks like this:

Automated Test
API Call to Power Automate Flow
Flow Creates CRM Data
Automated Test Calls Dataverse Web API
Validation of Data, Relationships, and Business Logic

This closes the loop: the test both creates and verifies the data.

Why Validate Through the API Instead of the UI

UI automation is slow, brittle, and environment‑dependent. API validation is:

  • Fast — milliseconds instead of minutes
  • Reliable — no DOM changes or UI latency
  • CI/CD‑friendly — runs headless
  • Precise — query exactly what you need
  • Secure — uses service principals, not user accounts

It’s the same API used internally by Power Apps and Power Automate.

Authentication: Giving Your Test Secure Access to Dataverse

To query Dataverse, your test needs an access token. The recommended approach is:

1. Create an Azure AD App Registration

This becomes your service principal.

2. Create an Application User in Dataverse

Assign it a minimal security role — often read‑only for validation.

3. Authenticate Using Client Credentials

Your test requests a token like this:

POST https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
client_id=xxxx
client_secret=xxxx
scope=https://{org}.crm.dynamics.com/.default
grant_type=client_credentials

This gives you a bearer token for API calls.

Querying Dataverse: Verifying That the Record Exists

Once authenticated, your test can query Dataverse directly.

Example: validate that a Contact was created:

GET https://{org}.crm.dynamics.com/api/data/v9.2/contacts?$filter=emailaddress1 eq 'test@example.com'

Your test should assert:

  • Status code 200
  • Exactly one record returned
  • Field values match expectations

This alone replaces the manual “log in and search” step.

Validating Field Values and Business Rules

Beyond existence, you can validate:

  • Default values set by plugins
  • Calculated fields
  • Rollup fields
  • Flow‑generated updates
  • Status or state transitions

Your test becomes a safety net for business logic, not just data creation.

Checking Related Records with OData Expansions

Dataverse supports $expand, allowing you to validate relationships in a single call.

Example: confirm the Contact is linked to the correct Account:

GET https://{org}.crm.dynamics.com/api/data/v9.2/contacts?
$filter=emailaddress1 eq 'test@example.com'
&$expand=parentcustomerid_account($select=name)

You can validate:

  • The Account exists
  • The relationship is correct
  • The Account has expected attributes

This is especially useful for scenarios where flows or plugins create related records.

Handling Asynchronous Operations and Retry Logic

Some CRM operations are asynchronous — plugins, flows, or rollups may take a moment to complete.

Your test should include:

  • Retry logic
  • Exponential backoff
  • A maximum timeout

This ensures your validation waits for the system to settle before asserting.

Full Example: Automated Test Flow from Trigger to Validation

A complete test might:

  1. Trigger a Power Automate flow via HTTP.
  2. Receive a correlation ID or expected email address.
  3. Wait briefly or use retry logic.
  4. Query Dataverse for the record.
  5. Validate:
    • Field values
    • Status codes
    • Related records
    • Business logic outcomes
  6. Optionally delete the test data.

This gives you a fully automated, repeatable test.

Code Snippet for API‑Based Validation (e.g., Python, C#, Postman)

Here’s a simple Python example:

import requests
token = get_token() # your OAuth function
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json"
}
url = f"https://{org}.crm.dynamics.com/api/data/v9.2/contacts"
params = {
"$filter": "emailaddress1 eq 'test@example.com'",
"$select": "firstname,lastname,emailaddress1"
}
response = requests.get(url, headers=headers, params=params)
data = response.json()
assert data['value'][0]['firstname'] == 'Jamie'

Swap in your own fields and entity names.

Cleaning Up Test Data (Optional but Recommended)

If your tests create data, consider cleaning it up:

  • Delete test records
  • Use a naming convention (e.g., “Test_”)
  • Run cleanup jobs in CI/CD

This keeps your CRM environment tidy and predictable.

Common Pitfalls and How to Avoid Them

  • Using user accounts instead of service principals  
    Leads to MFA issues and brittle tests.
  • Not waiting for async operations  
    Causes intermittent failures.
  • Querying too broadly  
    Always filter by unique identifiers.
  • Hard‑coding environment URLs  
    Use configuration variables.

Conclusion: Bringing True End‑to‑End Confidence to CRM Automation

By validating CRM data through the Dataverse Web API, you eliminate the last manual step in your automation pipeline. Your tests become faster, more reliable, and more meaningful — giving you true end‑to‑end confidence that your flows, plugins, and business logic are working exactly as intended.

Leave a comment