Understanding FakeXrmEasy Test Flow in Dynamics 365 CRM

 

Why We Add Entities to MergeSalesOrdersBase

When writing unit tests for Dynamics 365 CRM plugins using FakeXrmEasy, one of the most confusing concepts is:

Why do we need to add entities into _entities when we already use .ToEntityReference()?

This article explains the complete testing flow step by step.


The Real Problem

Suppose you have a Sales Order:

var salesOrder = new SalesOrder
{
new_ContosoSalesOrderType =
ContosoSalesOrderTypes.AcknowledgementTrue.ToEntityReference()
};

At first glance, it feels like the Sales Order Type already exists.

But internally, that is NOT true.

.ToEntityReference() only stores:

  • Logical Name
  • GUID

Example:

new_contososalesordertype
GUID = 12345

It does NOT store the actual entity fields.

So fields like:

new_AllowSalesOrderAcknowledgments
new_AllowMerging
new_AllowSubstitutes

are NOT available unless the entity itself is added into FakeXrmEasy.


Understanding the Complete Test Flow

Step 1 — Base Class Runs First

Your test inherits from:

public class given_sales_order_acknowledgements_true : MergeSalesOrdersBase

So before the actual test executes, the base setup runs:

[SetUp]
public void Init()

This method prepares all common entities.

Example:

_entities.Add(Companies.CompanyFood);
_entities.Add(Accounts.EnograIGA);
_entities.Add(ContosoSalesOrderTypes.Standard);

Think of this as seeding a fake CRM database.


Step 2 — Test Creates a Sales Order

Inside the test:

var salesOrder = new SalesOrder
{
new_ContosoSalesOrderType =
ContosoSalesOrderTypes.AcknowledgementTrue.ToEntityReference()
};

This only stores a lookup reference.

Equivalent to SQL:

SalesOrder
-----------
SalesOrderTypeId = 123

But the actual SalesOrderType row still does not exist.


Step 3 — FakeXrmEasy Initializes Database

When this line runs:

_context.Initialize(_entities);

FakeXrmEasy creates an in-memory CRM database using ONLY entities present in _entities.

Current database may contain:

✔ CompanyFood
✔ Accounts
✔ Products
✔ Standard Sales Order Type
❌ AcknowledgementTrue

If AcknowledgementTrue was never added, it does not exist in the fake database.


Step 4 — Plugin Executes

Now plugin execution starts:

_context.ExecutePluginWith<BuildSalesOrderAcknowledgement>(_pluginContext);

Inside the plugin, code usually retrieves related entities.

Example:

var salesOrderType = service.Retrieve(
new_ContosoSalesOrderType.EntityLogicalName,
id,
new ColumnSet(true));

FakeXrmEasy now searches its in-memory database.

It tries to find:

new_contososalesordertype
GUID = 123

If entity does not exist:

  • Retrieve fails
  • Plugin throws exception
  • FakeXrmEasy wraps it
  • You see errors like:
Correlation Id not found
Exception has been thrown by target of invocation

Why Standard Worked

Because your base setup already contains:

_entities.Add(ContosoSalesOrderTypes.Standard);

So FakeXrmEasy can successfully retrieve it.


Why AcknowledgementTrue Failed

Because you changed:

new_ContosoSalesOrderType =
ContosoSalesOrderTypes.AcknowledgementTrue.ToEntityReference()

but NEVER added:

_entities.Add(ContosoSalesOrderTypes.AcknowledgementTrue);

Therefore the fake CRM database does not contain that row.


Correct Fix

Add the entity before initialization:

_entities.Add(ContosoSalesOrderTypes.AcknowledgementTrue);

Now FakeXrmEasy database contains:

✔ Standard
✔ AcknowledgementTrue
✔ CompanyFood
✔ Accounts
✔ Products

Plugin retrieval succeeds.


Why Put It in MergeSalesOrdersBase

Because MergeSalesOrdersBase acts as:

Shared Test Database Setup

All tests inheriting from it automatically get:

  • common master data
  • lookup records
  • reference entities
  • configuration entities
  • products
  • companies
  • sales order types

without repeating setup in every test.

This keeps tests:

  • cleaner
  • reusable
  • maintainable
  • easier to debug

Simple Mental Model

CRM ConceptFakeXrmEasy Equivalent
Dataverse Row_entities.Add()
Lookup Field.ToEntityReference()
CRM Database_context.Initialize(_entities)
Plugin Retrieveservice.Retrieve()

Important Takeaway

EntityReference is NOT the entity itself.

This:

.ToEntityReference()

means only:

Table + GUID

To make plugin retrieval work, the actual entity must exist in FakeXrmEasy memory:

_entities.Add(entity)

Recommended Best Practice

Whenever your plugin retrieves related entities:

Always ensure those related entities are added into _entities before:

_context.Initialize(_entities)

Especially for:

  • lookup entities
  • configuration records
  • reference/master data
  • related parent entities
  • option/configuration entities

Final Example

Incorrect

new_ContosoSalesOrderType =
ContosoSalesOrderTypes.AcknowledgementTrue.ToEntityReference();

without:

_entities.Add(ContosoSalesOrderTypes.AcknowledgementTrue);

Correct

_entities.Add(ContosoSalesOrderTypes.AcknowledgementTrue);

var salesOrder = new SalesOrder
{
new_ContosoSalesOrderType =
ContosoSalesOrderTypes.AcknowledgementTrue.ToEntityReference()
};

_context.Initialize(_entities);

Now the plugin can retrieve the entity successfully.


Conclusion

Understanding the difference between:

  • EntityReference
  • actual entity records
  • FakeXrmEasy in-memory database

is one of the most important concepts in Dynamics CRM plugin unit testing.

Once this becomes clear, debugging FakeXrmEasy tests becomes much easier.ier.

Comments

Popular posts from this blog

🔍 Dataverse + Azure Integration: Choosing Between Synapse Link and Microsoft Fabric

⚡ Example: Rate Limiting in Azure API Management

👤 Anonymous Role in Power Pages – What It Is and When to Use It