Dynamics CRM 2011 Unit Test Part 10: Microsoft Fakes with workflow activity

Dynamics CRM 2011 Unit Test Part 1: Introduction and Series Contents

The complete sample code using Microsoft Fakes can be downloaded from MSDN sample gallery: Dynamics CRM unit test using Microsoft Fakes

Unit test CRM workflow activity is similar to unit test CRM plugin in terms of the interface we have to mock. There are three distinct points in any code activity unit test, first is how to correctly invoke Execute method since it is protected, second is how to pass in the InArgument parameters and the last is how to pass in required service as extensions.

1. Correctly invoke CodeActivity.Execute(CodeActivityContext executionContext)

Since CodeActivity.Execute(CodeActivityContext executionContext) is protected, the correct way to invoke is method is to construct an instance of System.Activities.WorkflowInvoker and pass in an instance of custom code workflow activity. we can call the Invoke method on the WorkflowInvoker instance to trigger the execution of CodeActivity.Execute method.


AddMemberTeamActivity target = new AddMemberTeamActivity();

var invoker = new WorkflowInvoker(target);

var outputs = invoker.Invoke(inputs);

2. Correctly pass in InArgument<T> properties

the InArgument<T> properties need to be passed in as a dictionary when call WorkflowInvoker.Invoke method


var inputs = new Dictionary<string, object>
 {
 { "User", new EntityReference("systemuser", expectedUserId) },
 { "Team", new EntityReference("team", expectedTeamId) }
 };

var outputs = invoker.Invoke(inputs);

3. Pass in required service as extensions

required service can be added to WorkflowInvoker.Extensions property


var invoker = new WorkflowInvoker(target);
 invoker.Extensions.Add<ITracingService>(() => tracingService);
 invoker.Extensions.Add<IWorkflowContext>(() => workflowContext);
 invoker.Extensions.Add<IOrganizationServiceFactory>(() => factory);

Code Under Test


public sealed class AddMemberTeamActivity : CodeActivity
 {
 [RequiredArgument]
 [Input("User to Add")]
 [ReferenceTarget("systemuser")]
 public InArgument<EntityReference> User { get; set; }

[RequiredArgument]
 [Input("Team to Add To")]
 [ReferenceTarget("team")]
 public InArgument<EntityReference> Team { get; set; }

/// <summary>
 /// Executes the workflow activity.
 /// </summary>
 /// <param name="executionContext">The execution context.</param>
 protected override void Execute(CodeActivityContext executionContext)
 {
 // Create the tracing service
 ITracingService tracingService = executionContext.GetExtension<ITracingService>();

if (tracingService == null)
 {
 throw new InvalidPluginExecutionException("Failed to retrieve tracing service.");
 }

tracingService.Trace("Entered AddMemberTeamActivity.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}",
 executionContext.ActivityInstanceId,
 executionContext.WorkflowInstanceId);

// Create the context
 IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

if (context == null)
 {
 throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
 }

tracingService.Trace("AddMemberTeamActivity.Execute(), Correlation Id: {0}, Initiating User: {1}",
 context.CorrelationId,
 context.InitiatingUserId);

IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
 IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

try
 {
 EntityReference user = this.User.Get(executionContext);
 EntityReference team = this.Team.Get(executionContext);

if (!IsMemberInTeam(service, team.Id, user.Id))
 {
 OrganizationRequest request = new AddMembersTeamRequest { MemberIds = new Guid[] { user.Id }, TeamId = team.Id };

var response = service.Execute(request) as AddMembersTeamResponse;
 }
 }
 catch (FaultException<OrganizationServiceFault> e)
 {
 tracingService.Trace("Exception: {0}", e.ToString());

// Handle the exception.
 throw;
 }

tracingService.Trace("Exiting AddMemberTeamActivity.Execute(), Correlation Id: {0}", context.CorrelationId);
 }

internal bool IsMemberInTeam(IOrganizationService service, Guid teamId, Guid memberId)
 {
 OrganizationServiceContext context = new OrganizationServiceContext(service);

var query = from relationship in context.CreateQuery("teammembership")
 where relationship.GetAttributeValue<Guid>("teamid") == teamId
 && relationship.GetAttributeValue<Guid>("systemuserid") == memberId
 select relationship;

return query.FirstOrDefault() != null;
 }
 }

Unit Test


[TestClass]
 public class AddMemberTeamActivityTest
 {
 [TestMethod]
 public void ExecuteTest()
 {
 //
 // Arrange
 //
 Guid actualUserId = Guid.NewGuid();
 Guid actualTeamId = Guid.NewGuid();
 var workflowUserId = Guid.NewGuid();
 var workflowCorrelationId = Guid.NewGuid();
 var workflowInitiatingUserId = Guid.NewGuid();

// IOrganizationService
 var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.ExecuteOrganizationRequest = r =>
 {
 AddMembersTeamRequest request = r as AddMembersTeamRequest;
 actualUserId = request.MemberIds[0];
 actualTeamId = request.TeamId;
 return new AddMembersTeamResponse();
 };

// IWorkflowContext
 var workflowContext = new Microsoft.Xrm.Sdk.Workflow.Fakes.StubIWorkflowContext();
 workflowContext.UserIdGet = () =>
 {
 return workflowUserId;
 };
 workflowContext.CorrelationIdGet = () =>
 {
 return workflowCorrelationId;
 };
 workflowContext.InitiatingUserIdGet = () =>
 {
 return workflowInitiatingUserId;
 };

// ITracingService
 var tracingService = new Microsoft.Xrm.Sdk.Fakes.StubITracingService();
 tracingService.TraceStringObjectArray = (f, o) =>
 {
 Debug.WriteLine(f, o);
 };

// IOrganizationServiceFactory
 var factory = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationServiceFactory();
 factory.CreateOrganizationServiceNullableOfGuid = id =>
 {
 return service;
 };

var expectedUserId = Guid.NewGuid();
 var expectedTeamId = Guid.NewGuid();

AddMemberTeamActivity target = new AddMemberTeamActivity();
 using (ShimsContext.Create())
 {
 var fakeTarget = new DynamicsCRMUnitTest.Workflow.Fakes.ShimAddMemberTeamActivity(target);
 fakeTarget.IsMemberInTeamIOrganizationServiceGuidGuid = (svc, teamId, memberId) =>
 {
 return false;
 };

var invoker = new WorkflowInvoker(target);
 invoker.Extensions.Add<ITracingService>(() => tracingService);
 invoker.Extensions.Add<IWorkflowContext>(() => workflowContext);
 invoker.Extensions.Add<IOrganizationServiceFactory>(() => factory);

var inputs = new Dictionary<string, object>
 {
 { "User", new EntityReference("systemuser", expectedUserId) },
 { "Team", new EntityReference("team", expectedTeamId) }
 };

//
 // Act
 //
 var outputs = invoker.Invoke(inputs);
 }

//
 // Assert
 //
 Assert.AreEqual(expectedUserId, actualUserId);
 Assert.AreEqual(expectedTeamId, actualTeamId);
 }

[TestMethod]
 public void IsMemberInTeamTest()
 {
 //
 // Arrange
 //
 Guid userId = Guid.NewGuid();
 Guid teamId = Guid.NewGuid();
 bool expected = true;

AddMemberTeamActivity target = new AddMemberTeamActivity();

// IOrganizationService
 var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.ExecuteOrganizationRequest = r =>
 {
 List<Entity> entities = new List<Entity>
 {
 new Entity()
 };

var response = new RetrieveMultipleResponse
 {
 Results = new ParameterCollection
 {
 { "EntityCollection", new EntityCollection(entities) }
 }
 };

return response;
 };

//
 // Act
 //
 var actual = target.IsMemberInTeam(service, teamId, userId);

//
 // Assert
 //
 Assert.AreEqual(expected, actual);
 }
 }

Advertisements

Dynamics CRM 2011 Unit Test Part 9: Microsoft Fakes with CRM plugin

Dynamics CRM 2011 Unit Test Part 1: Introduction and Series Contents

The complete sample code using Microsoft Fakes can be downloaded from MSDN sample gallery: Dynamics CRM unit test using Microsoft Fakes

Unit test CRM plugin is straightforward as well, it is just a bit tedious. IPlugin.Execute only accept one parameter which is IServiceProvider. Through IServiceProvider we can retrieve at least 3 interface and we need to set up 5 interface, which will be IOrganizationService, IPluginExecutionContext, ITracingService, IOrganizationServiceFactory and IServiceProvider.

Suppose we have a sample Dynamics CRM plugin, which is called after a contact is created within Dynamics CRM, if the parent customer is set to an account, the number of employees attribute of that account will be increased by one.

Code Under Test


public class Plugin : IPlugin
 {
 private string _unsecure, _secure;

/// <summary>
 /// Alias of the image registered for the snapshot of the
 /// primary entity's attributes after the core platform operation executes.
 /// The image contains the following attributes:
 /// parentcustomerid
 ///
 /// Note: Only synchronous post-event and asynchronous registered plug-ins
 /// have PostEntityImages populated.
 /// </summary>
 private readonly string postImageAlias = "PostCreateImage";

public Plugin(string unsecure, string secure)
 {
 _unsecure = unsecure;
 _secure = secure;
 }

public void Execute(IServiceProvider serviceProvider)
 {
 // Obtain the execution context service from the service provider.
 var pluginExecutionContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

if (pluginExecutionContext.Stage == 40 && pluginExecutionContext.MessageName == "Create" && pluginExecutionContext.PrimaryEntityName == "contact")
 {
 // Obtain the tracing service from the service provider.
 var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

// Obtain the Organization Service factory service from the service provider
 IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

// Use the factory to generate the Organization Service.
 var organizationService = factory.CreateOrganizationService(pluginExecutionContext.UserId);

Entity postImageEntity = (pluginExecutionContext.PostEntityImages != null && pluginExecutionContext.PostEntityImages.Contains(this.postImageAlias)) ? pluginExecutionContext.PostEntityImages[this.postImageAlias] : null;

// when a contact is created with parent account, increase number of employees for that account
 if (postImageEntity != null && postImageEntity.Contains("parentcustomerid"))
 {
 EntityReference parentCustomer = postImageEntity.GetAttributeValue<EntityReference>("parentcustomerid");

if (parentCustomer != null && parentCustomer.LogicalName.ToLowerInvariant() == "account")
 {
 tracingService.Trace("Parent account id: {0}.", parentCustomer.Id);

Entity parentAccount = organizationService.Retrieve("account", parentCustomer.Id, new Microsoft.Xrm.Sdk.Query.ColumnSet("numberofemployees"));

int numberOfEmployees = 0;
 if (parentAccount.Contains("numberofemployees"))
 {
 numberOfEmployees = parentAccount.GetAttributeValue<int>("numberofemployees");
 }

parentAccount["numberofemployees"] = numberOfEmployees + 1;

organizationService.Update(parentAccount);
 }
 }
 }
 }
 }

Unit Test


[TestClass]
 public class PluginTest
 {
 /// <summary>
 ///A test for Execute
 ///</summary>
 [TestMethod()]
 public void ExecuteTest()
 {
 //
 // Arrange
 //
 string unsecure = "unsecure";
 string secure = "secure";
 Plugin target = new Plugin(unsecure, secure);

var accountId = Guid.NewGuid();
 var previousNumber = 3;
 var expected = 4;
 var actual = 0;

// IOrganizationService
 var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.RetrieveStringGuidColumnSet = (entityName, id, columns) =>
 {
 return new Microsoft.Xrm.Sdk.Entity("account")
 {
 Id = accountId,
 Attributes = { { "numberofemployees", previousNumber } }
 };
 };
 service.UpdateEntity = (entity) =>
 {
 actual = entity.GetAttributeValue<int>("numberofemployees");
 };

// IPluginExecutionContext
 var pluginExecutionContext = new Microsoft.Xrm.Sdk.Fakes.StubIPluginExecutionContext();
 pluginExecutionContext.StageGet = () => { return 40; };
 pluginExecutionContext.MessageNameGet = () => { return "Create"; };
 pluginExecutionContext.PrimaryEntityNameGet = () => { return "contact"; };
 pluginExecutionContext.PostEntityImagesGet = () =>
 {
 return new EntityImageCollection
 {
 { "PostCreateImage", new Microsoft.Xrm.Sdk.Entity("contact")
 {
 Attributes = { { "parentcustomerid", new EntityReference("account", accountId) } }
 }
 }
 };
 };

// ITracingService
 var tracingService = new Microsoft.Xrm.Sdk.Fakes.StubITracingService();
 tracingService.TraceStringObjectArray = (f, o) =>
 {
 Debug.WriteLine(f, o);
 };

// IOrganizationServiceFactory
 var factory = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationServiceFactory();
 factory.CreateOrganizationServiceNullableOfGuid = id =>
 {
 return service;
 };

// IServiceProvider
 var serviceProvider = new System.Fakes.StubIServiceProvider();
 serviceProvider.GetServiceType = t =>
 {
 if (t == typeof(IPluginExecutionContext))
 {
 return pluginExecutionContext;
 }
 else if (t == typeof(ITracingService))
 {
 return tracingService;
 }
 else if (t == typeof(IOrganizationServiceFactory))
 {
 return factory;
 }

return null;
 };

//
 // Act
 //
 target.Execute(serviceProvider);

//
 // Assert
 //
 Assert.AreEqual(expected, actual);
 }
 }

Dynamics CRM 2011 Unit Test Part 8: Microsoft Fakes with IOrganizationService

Dynamics CRM 2011 Unit Test Part 1: Introduction and Series Contents

The complete sample code using Microsoft Fakes can be downloaded from MSDN sample gallery: Dynamics CRM unit test using Microsoft Fakes

Isolate IOrganizationService method call in unit test code should be very simple and straightforward, since it is a well defined interface. With Microsoft Fakes you can use the generated Stub types contained in the generated fake assembly.

Code Under Test


public class OrganizationServiceMethods
 {
 private IOrganizationService _service;

public OrganizationServiceMethods(IOrganizationService service)
 {
 _service = service;
 }

public IEnumerable<Guid> RetrieveAccountIdByName(string name)
 {
 QueryByAttribute query = new QueryByAttribute("account")
 {
 ColumnSet = new ColumnSet("accountid")
 };
 query.Attributes.Add("name");
 query.Values.Add(name);

var result = _service.RetrieveMultiple(query);

List<Guid> ids = new List<Guid>();

foreach (var entity in result.Entities)
 {
 ids.Add(entity.GetAttributeValue<Guid>("accountid"));
 }

return ids;
 }
 }

Unit Test


[TestMethod]
 public void RetrieveAccountIdByNameTest()
 {
 //
 // Arrange
 //
 IEnumerable<Guid> actual;
 IEnumerable<Guid> expected = new List<Guid> { Guid.NewGuid(), Guid.NewGuid() };

int callCount = 0;

var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.RetrieveMultipleQueryBase = (query) =>
 {
 callCount++;

var results = new EntityCollection();

results.Entities.AddRange(
 new Entity("account") { Attributes = { { "accountid", expected.ElementAt(0) } } },
 new Entity("account") { Attributes = { { "accountid", expected.ElementAt(1) } } });

return results;
 };

OrganizationServiceMethods target = new OrganizationServiceMethods(service);

//
 // Act
 //
 actual = target.RetrieveAccountIdByName("TestName");

//
 // Assert
 //
 Assert.AreEqual(callCount, 1); // verify OrganizationServiceContext.RetrieveVersion is called once

Assert.AreEqual(expected.Count(), actual.Count());
 Assert.AreEqual(expected.ElementAt(0), actual.ElementAt(0));
 Assert.AreEqual(expected.ElementAt(1), actual.ElementAt(1));
 }

Dynamics CRM 2011 Unit Test Part 7: Microsoft Fakes with CrmOrganizationServiceContext through IOrganizationService

Dynamics CRM 2011 Unit Test Part 1: Introduction and Series Contents

The complete sample code using Microsoft Fakes can be downloaded from MSDN sample gallery: Dynamics CRM unit test using Microsoft Fakes

In a previous post (Part 4: Microsoft Fakes with CrmOrganizationServiceContext), I have describe how to use run time redirect delegate feature of Microsoft Fakes to unit test CrmOrganizationServiceContext. I consider this a direct approach since you do not need to understand the IOrganizationService API and you do not need to know all the underlining messages. If you know IOrganizationService API and underlining messages, there is also an indirect approach to unit test CrmOrganizationServiceContext, which is to mock the underlining IOrganizationService.

CrmOrganizationServiceContext is SDK Extensions contained in Microsoft.Xrm.Client assembly. CrmOrganizationServiceContext allows the entity objects produced by the data context to participate in the WCF Data Services framework. CrmOrganizationServiceContext provide methods from various OrganizationRequest, which means a method based implementation of the message API. These methods are defined as extension methods, to use these methods we have to include the Microsoft.Xrm.Client.Messages namespace.

For more information on CrmOrganizationServiceContext, see Developer Extensions Context Object Model

CrmOrganizationServiceContext will perform all its method work through IOrganizationService.Execute method. We need to provide an instance of IOrganizationService to construct OrganizationServiceContext, OrganizationServiceContext is going to translate LINQ to CRM query into RetrieveMultipleRequest and execute that OrganizationRequest by calling IOrganizationService.Execute. If we mock IOrganizationService properly, we can isolate LINQ to CRM query unit test.

Code Under Test


public class CrmContextMethods2
 {
 private CrmOrganizationServiceContext _crmContext;

public CrmContextMethods2(IOrganizationService service)
 {
 _crmContext = new CrmOrganizationServiceContext(service);
 }

public string RetrieveVersion()
 {
 var version = _crmContext.RetrieveVersion();

return version;
 }

public Guid CreateAccount(string name)
 {
 var entity = new Entity("account")
 {
 Attributes = new Microsoft.Xrm.Sdk.AttributeCollection
 {
 { "name", name }
 }
 };

var id = _crmContext.Create(entity);

return id;
 }
 }

Unit Test


[TestClass]
 public class CrmContextMethods2Test
 {
 [TestMethod]
 public void CreateAccountTest()
 {
 //
 // Arrange
 //
 string accountName = "abcabcabc";
 Guid actual;
 Guid expected = Guid.NewGuid();

int callCount = 0;
 Entity entity = null;

var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.CreateEntity = e =>
 {
 callCount++;
 entity = e;
 return expected;
 };

CrmContextMethods2 target = new CrmContextMethods2(service);

//
 // Act
 //
 actual = target.CreateAccount(accountName);

//
 // Assert
 //
 Assert.AreEqual(callCount, 1); // verify OrganizationServiceContext.Create is called once
 Assert.IsNotNull(entity); // verify OrganizationServiceContext.Create is called with not null object
 Assert.AreEqual(entity.LogicalName, "account"); // verify OrganizationServiceContext.Create is called with entity with proper entity name
 Assert.AreEqual(entity.GetAttributeValue<string>("name"), accountName); // verify OrganizationServiceContext.Create is called with entity with proper value set on name attribute

Assert.AreEqual(expected, actual);
 }

[TestMethod]
 public void RetrieveVersionTest()
 {
 //
 // Arrange
 //
 string actual;
 string expected = "5.0.9690.2243";

int callCount = 0;

var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.ExecuteOrganizationRequest = r =>
 {
 callCount++;

return new RetrieveVersionResponse
 {
 Results = new ParameterCollection
 {
 { "Version", expected }
 }
 };
 };

CrmContextMethods2 target = new CrmContextMethods2(service);

//
 // Act
 //
 actual = target.RetrieveVersion();

//
 // Assert
 //
 Assert.AreEqual(callCount, 1); // verify OrganizationServiceContext.RetrieveVersion is called once

Assert.AreEqual(expected, actual);
 }

}

Part 6: Microsoft Fakes with OrganizationServiceContext through IOrganizationService

Dynamics CRM 2011 Unit Test Part 1: Introduction and Series Contents

The complete sample code using Microsoft Fakes can be downloaded from MSDN sample gallery: Dynamics CRM unit test using Microsoft Fakes

In a previous post (Part 3: Microsoft Fakes with OrganizationServiceContext), I have describe how to use run time redirect delegate feature of Microsoft Fakes to unit test OrganizationServiceContext. I consider this a direct approach since you do not need to understand the IOrganizationService API and you do not need to know all the underlining messages. If you know IOrganizationService API and underlining messages, there is also an indirect approach to unit test OrganizationServiceContext, which is to mock the underlining IOrganizationService.

We need to provide an instance of IOrganizationService to construct OrganizationServiceContext, if we mock IOrganizationService properly, we can isolate OrganizationServiceContext unit test.

Code under test


public class ContextMethods2
 {
 private OrganizationServiceContext _context;

public ContextMethods2(IOrganizationService service)
 {
 _context = new OrganizationServiceContext(service);
 }

public Guid CreateAccount(string name)
 {
 var entity = new Entity("account")
 {
 Attributes = new Microsoft.Xrm.Sdk.AttributeCollection
 {
 { "name", name }
 }
 };

_context.AddObject(entity);

var results = _context.SaveChanges();

return entity.Id;
 }
 }

Unit Test


[TestClass]
 public class ContextMethods2Test
 {
 [TestMethod]
 public void CreateAccountTest()
 {
 //
 // Arrange
 //
 string accountName = "abcabcabc";
 Guid actual;
 Guid expected = Guid.Empty;

int callCount = 0;
 Entity entity = null;

var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();
 service.ExecuteOrganizationRequest = r =>
 {
 callCount++;

var request = r as CreateRequest;
 entity = request.Target;
 expected = entity.Id;

return new CreateResponse
 {
 Results = new ParameterCollection
 {
 { "id", expected }
 }
 };
 };

ContextMethods2 target = new ContextMethods2(service);

//
 // Act
 //
 actual = target.CreateAccount(accountName);

//
 // Assert
 //
 Assert.AreEqual(callCount, 1); // verify OrganizationServiceContext.AddObject is called once
 Assert.IsNotNull(entity); // verify OrganizationServiceContext.AddObject is called with not null object
 Assert.AreEqual(entity.LogicalName, "account"); // verify OrganizationServiceContext.AddObject is called with entity with proper entity name
 Assert.AreEqual(entity.GetAttributeValue<string>("name"), accountName); // verify OrganizationServiceContext.AddObject is called with entity with proper value set on name attribute

Assert.AreEqual(expected, actual);
 }
 }

Dynamics CRM 2011 Unit Test Part 5: Microsoft Fakes with LINQ query through IOrganizationService

Dynamics CRM 2011 Unit Test Part 1: Introduction and Series Contents

The complete sample code using Microsoft Fakes can be downloaded from MSDN sample gallery: Dynamics CRM unit test using Microsoft Fakes

In a previous post (Part 2: Microsoft Fakes with LINQ query), I have describe how to use run time redirect delegate feature of Microsoft Fakes to unit test LINQ to CRM query. I consider this a direct approach since you do not need to understand the IOrganizationService API and you do not need to know all the underlining messages. If you know IOrganizationService API and underlining messages, there is also an indirect approach to unit test LINQ to CRM query, which is to mock the underlining IOrganizationService.

To use LINQ to query CRM data, we need to use OrganizationServiceContext or a deriving class such as CrmOrganizationServiceContext which is SDK Extensions contained in Microsoft.Xrm.Client assembly, or a deriving class created by the CrmSvcUtil tool. The OrganizationServiceContext class contains an underlying LINQ query provider that translates LINQ queries from Microsoft Visual C# or Microsoft Visual Basic .NET syntax into the query API used by Microsoft Dynamics CRM.

We need to provide an instance of IOrganizationService to construct OrganizationServiceContext, OrganizationServiceContext is going to translate LINQ to CRM query into RetrieveMultipleRequest and execute that OrganizationRequest by calling IOrganizationService.Execute. If we mock IOrganizationService properly, we can isolate LINQ to CRM query unit test.

Code under test


public class LINQToCRM2
 {
 private OrganizationServiceContext _context;

public LINQToCRM2(IOrganizationService service)
 {
 _context = new OrganizationServiceContext(service);
 }

public IEnumerable<Entity> RetrieveAccountsByName(string name)
 {
 var query = from account in _context.CreateQuery("account")
 where account.GetAttributeValue<string>("name") == name
 select account;

var accountList = new List<Entity>();

foreach (var entity in query)
 {
 accountList.Add(entity);
 }

//We can simply call query.ToList()
 //foreach loop here is to demonstrate item Enumeration

return accountList;
 }

public Entity RetrieveAccountsById(Guid id)
 {
 var query = from account in _context.CreateQuery("account")
 where account.GetAttributeValue<Guid>("accountid") == id
 select account;

var accountEntity = query.FirstOrDefault();

return accountEntity;
 }
 }

Unit Test


[TestClass]
 public class LINQToCRM2Test
 {
 [TestMethod]
 public void RetrieveAccountsByNameTest()
 {
 //
 // Arrange
 //
 var entity1 = new Microsoft.Xrm.Sdk.Entity("account");
 entity1.Id = Guid.NewGuid();
 entity1["name"] = "abcabcabc";

var entity2 = new Microsoft.Xrm.Sdk.Entity("account");
 entity2.Id = Guid.NewGuid();
 entity2["name"] = "123123123";

var entity3 = new Microsoft.Xrm.Sdk.Entity("account");
 entity3.Id = Guid.NewGuid();
 entity3["name"] = "a1b2c3a1b2c3";

var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();

service.ExecuteOrganizationRequest = r =>
 {
 List<Entity> entities = new List<Entity>
 {
 entity1, entity2
 };

var response = new RetrieveMultipleResponse
 {
 Results = new ParameterCollection
 {
 { "EntityCollection", new EntityCollection(entities) }
 }
 };

return response;
 };

string accountName = "abcabcabc";
 IEnumerable<Microsoft.Xrm.Sdk.Entity> actual;
 LINQToCRM2 target = new LINQToCRM2(service);

//
 // Act
 //
 actual = target.RetrieveAccountsByName(accountName);

//
 // Assert
 //
 Assert.AreEqual(2, actual.Count());
 Assert.AreEqual(entity1, actual.ElementAt(0));
 Assert.AreEqual(entity2, actual.ElementAt(1));
 }

[TestMethod]
 public void RetrieveAccountsByIdTest()
 {
 //
 // Arrange
 //
 Guid id = Guid.NewGuid();

Microsoft.Xrm.Sdk.Entity expected = new Microsoft.Xrm.Sdk.Entity { Id = id };

var service = new Microsoft.Xrm.Sdk.Fakes.StubIOrganizationService();

service.ExecuteOrganizationRequest = r =>
 {
 List<Entity> entities = new List<Entity>
 {
 expected
 };

var response = new RetrieveMultipleResponse
 {
 Results = new ParameterCollection
 {
 { "EntityCollection", new EntityCollection(entities) }
 }
 };

return response;
 };

Microsoft.Xrm.Sdk.Entity actual;
 LINQToCRM2 target = new LINQToCRM2(service);

//
 // Act
 //
 actual = target.RetrieveAccountsById(id);

//
 // Assert
 //
 Assert.AreEqual(expected, actual);
 }
 }