Integration testing patterns for Dynamics 365
How to test integrations for Dynamics 365 — unit, contract, integration, end-to-end tests, and the patterns that catch regressions before production.
An untested integration is a future incident. Dynamics 365 integrations are particularly vulnerable: multiple systems, complex business rules, evolving schemas. Integration testing is the discipline that catches problems before users do. Mature operations have multi-layer test strategies; immature ones discover issues in production.
Testing pyramid.
- Unit tests — fast, narrow, isolated.
- Contract tests — interface compliance.
- Integration tests — multi-component, real dependencies.
- End-to-end tests — full system, real systems.
Each layer catches different defects; balance speed and coverage.
Unit tests for integration code.
- Test individual functions / classes.
- Mock external dependencies.
- Fast execution.
- Run on every commit.
Catch logic bugs before reaching anything external.
Mocking external systems.
- Mock Dataverse API — for testing logic.
- Mock external systems — assumed responses.
- Test doubles for asynchronous calls.
Pros: fast, isolated. Cons: assumes mock matches reality; gaps possible.
Contract testing. Verify interface compliance:
- Consumer-driven — consumer specifies expected interface.
- Provider verifies they meet the contract.
- Catches breaking changes early.
Tools: Pact, Spring Cloud Contract. Less common in Dynamics world; the concept is useful.
Integration tests.
- Multiple components together.
- Real or test-environment dependencies.
- Slower than unit; faster than full e2e.
- Specific scenarios.
Catch bugs in component interaction.
End-to-end tests.
- Full system stack.
- Real Dynamics environment (test instance).
- Real external systems (test environments).
- Slowest; full-coverage scenarios.
Catch system-level issues; can't catch interaction logic bugs (that's integration test job).
Test environment strategy.
- Dev sandboxes — for development.
- Test environments — for integration testing.
- UAT environments — production-like.
- Production-like staging — final pre-production validation.
Each level has different fidelity to production.
Test data management. Critical:
- Synthetic data — generated.
- Anonymised production data — realistic but safe.
- Curated test datasets — covering specific scenarios.
Test data freshness affects test reliability.
Test cases for integrations.
- Happy path — primary flow.
- Edge cases — boundary conditions.
- Failure modes — error handling.
- Idempotency — duplicate processing.
- Concurrency — parallel operations.
- Performance — load behaviour.
- Schema evolution — backward compatibility.
Each warrants test coverage.
Asynchronous integration testing.
- Trigger the action.
- Wait for asynchronous completion.
- Assert end state.
- Timeout if too slow.
The wait is challenging; polling vs callback; timeout balance.
Test isolation.
- Each test isolated from others.
- Setup test data per test.
- Cleanup after.
Without isolation, test order matters; flaky tests.
Test naming and organisation.
- Behaviour-driven names —
Should_create_order_when_valid_quote. - Grouped by feature.
- Tagged for filtering (smoke, regression, etc.).
Readable test names enable maintenance and debugging.
Continuous testing.
- CI runs unit + fast integration on every commit.
- Nightly runs e2e suite.
- Pre-deployment runs full regression.
- Smoke tests post-deployment to verify health.
Each cadence different.
Performance testing.
- Load test — sustained load.
- Stress test — pushing limits.
- Spike test — sudden burst.
- Soak test — extended duration.
For integrations expected to handle volume, performance testing essential.
Tools.
- xUnit, NUnit, MSTest — .NET unit testing.
- Specflow — BDD-style.
- Postman / Newman — API testing.
- K6, JMeter — performance.
- Power Apps Test Engine — for canvas apps.
- Custom test harness for Dynamics-specific.
Each has place; toolchain depends on team.
Test code as production code. Test quality matters:
- Readable.
- Maintainable.
- Reliable (not flaky).
- Documented.
Flaky tests get ignored; bad tests worse than no tests.
Flaky test handling.
- Identify flaky tests.
- Investigate root cause (timing, isolation, data).
- Fix or remove.
- Don't tolerate flakiness — it erodes trust in test suite.
Schema evolution testing.
- Forward compatibility — new data format readable by old consumer.
- Backward compatibility — old data readable by new consumer.
Both essential for integrations that evolve.
Negative testing. What happens when things go wrong:
- Invalid data input.
- Network failure.
- Downstream unavailable.
- Schema mismatch.
Negative tests catch reliability bugs; often more valuable than positive.
Test environments and CI/CD integration.
- Pipeline triggers tests automatically.
- Test results gate deployment.
- Failed tests block progression.
Tests as quality gate.
Common pitfalls.
- No integration tests. Bugs found in production.
- Tests only happy path. Edge cases hit users first.
- Flaky tests tolerated. Trust in suite erodes.
- Test environments unrepresentative. Tests pass; production fails.
- No performance testing. Production load surprises.
- Tests skip when slow. Convenience over rigour.
- Test data leaks. Production data in test environments; compliance issue.
Coverage targets.
- Code coverage 60-80% typical for production code.
- Critical paths 100%.
- Less critical lower.
Coverage isn't quality alone; thoughtful tests beat high coverage with shallow tests.
Mutation testing. Advanced:
- Introduce small code changes (mutations).
- Run tests.
- Tests should fail (catch the mutation).
- Tests that don't catch mutations are weak.
Reveals weak tests.
Strategic positioning. Integration testing is investment in reliability. Mature operations have multi-layer test strategies; immature ones discover issues in production. The investment pays back through fewer production incidents, faster feature delivery, and confident deployments.
For architects:
- Build test strategy from start.
- Layer tests appropriately.
- Maintain test environments.
- Integrate with CI/CD.
- Treat tests as production code.
The teams that test rigorously ship reliably; the teams that don't ship anxiously. The difference is testing discipline; the cost is engineering time; the benefit is operational confidence.
Related guides
- Circuit breakers in Dynamics 365 integrationsHow the circuit-breaker pattern protects Dynamics 365 integrations from cascading failures — implementation in Azure Functions, Logic Apps, and Dataverse plug-ins, with operational tuning.
- Observability for Dynamics 365 integrationsHow to build observability into Dynamics 365 integrations — logs, metrics, traces, correlation IDs, and the patterns that make production integration health visible.
- OpenTelemetry with Dynamics 365 integrationsHow OpenTelemetry standardises observability in Dynamics 365 architectures — instrumentation, exporters, distributed tracing, and the path to vendor-neutral observability.
- Retry policies with Azure services for Dynamics 365 integrationsHow to implement retry policies in Azure-based Dynamics 365 integrations — exponential backoff, idempotency, circuit-breaker integration, and the patterns that handle transient failures gracefully.
- Integration patterns for Dynamics 365 CRMThe standard integration patterns for CRM-side Dynamics 365 — webhooks, Dataverse plug-ins, Service Bus integration, virtual tables, and pull vs push.