简体   繁体   中英

LINQ query results not filtered when mocking IOrganizationService (Dynamics CRM)

I am having a problem unit testing my code that queries Dynamics CRM 2015.

I use the Moq framework and mock the IOrganizationService as follows:

IList<Account> accounts = new List<Account> {/*...*/};
IList<IEntity> expected = new List<Entity>(accounts);
var collection = new EntityCollection(expected);
var retrieveMultipleResponse = new RetrieveMultipleResponse
{
    Results = new ParameterCollection
    {
        { "EntityCollection", collection}
    }
};
var mockOrganizationService = new Mock<IOrganizationService>();
mockOrganizationService.Setup(os => os.Execute(
    It.IsAny<RetrieveMultipleRequest>())).Returns(retrieveMultipleResponse);

So, the IOrganizationService mock would always return the same predefined list of accounts, no matter what the request is like.

This is the code I am trying to test:

var query = serviceContext.AccountSet.Where(
                a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();

When this code is executed against a real CRM instance, it works as expected.

Using a mocked IOrganizationService , the code does not work anymore. In the debugger, I can see that AccountSet returns the expected account list (the one I set up during mocking). However, the Where method does not seem to get executed, and query contains all the account entities. So, the call to FirstOrDefault returns only the first one, and not the result of calling the Where method.

If I modify the code as follows, it also starts working during unit testing:

var query = serviceContext.AccountSet.ToList().Where(
                    a => a.AccountId != null && a.AccountId.Value == guid)
var account = query.FirstOrDefault();

If I understand correctly, this code retrieves all the accounts, and filters them locally (not in CRM). This is fine for unit testing, but this would not be acceptable in the real application.

Could anyone please advise what I am doing wrong? Thank you!

Edit :

We ended up mocking serviceContext instead because we call methods (or properties) on it directly from the client code, and not the ones on IOrganizationService . I think that mocking IOrganizationService should only make sense if the code we want to test uses IOrganizationService directly and not via serviceContext . Otherwise, we have something like two-level mocking, and it becomes messy.

Please give a try to FakeXrmEasy . There are some introduction videos and many different testing examples.

By using FakeXrmEasy mocks are already handled by the framework, therefore reducing the amount of boilerplate code just to setup your test.

I've been working on it since 2014, and it is MIT licensed. Actually, if anyone would like to contribute to the project it would be super awesome! :)

EDIT : Just adding a link to a blog post which compares FakeXrmEasy against other .NET mocking frameworks. The purpose is nothing but to be able to have as many work done for Dynamics CRM as possible. With other .NET mocking frameworks there is basically too much to mock, every single time.

The Where clause becomes a part of the query executed against the OrganizationService which in your case is mocked to always return the full accounts list regardless of conditions. You could add more logic to your moq, but generally that's not necessary in unit tests as your goal is to test your business logic and not your ability to mock the OrganizationService .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM