OData / odata.net

ODataLib: Open Data Protocol - .NET Libraries and Frameworks
https://docs.microsoft.com/odata
Other
687 stars 349 forks source link

How to use the generated ODataClient in unit tests? #1167

Closed kornakar closed 6 years ago

kornakar commented 6 years ago

I couldn't find any documentation on how to use the library in unit tests. My case is related to using the code generated with the ODataT4CodeGenerator.tt. The generated code doesn't have any interfaces and most of the constructors are internal, so the only way to use it in unit tests seems to be using Microsoft Fakes library.

But even with the MS Fakes making everything work seems pretty complicated. Is it possible that you could provide some documentation on how we should use the generated code classes when unit testing code?

Assemblies affected

7.4.4.20330

Additional detail

I've found a way to mock some of the IQueryable methods in the main class (System, DataServiceContext) like this:

ShimSystem.AllInstances.InsurancesGet = i => GetDataServiceQuery(insurances.AsEnumerable());

private DataServiceQuery<T> GetDataServiceQuery<T>(IEnumerable<T> data)
{
    IQueryable<T> queryableData = data.AsQueryable();

    StubDataServiceContext context = new StubDataServiceContext();

    var queryShim = new ShimDataServiceQuery<T>
    {
        ExpressionGet = () => queryableData.Expression,
        ElementTypeGet = () => queryableData.ElementType,
        ProviderGet = () => queryableData.Provider,
        GetEnumerator = () => queryableData.GetEnumerator(),
        ContextGet = () => context,
        ExpandString = (s) => GetDataServiceQuery(default(T)),
        InstanceBehavior = ShimBehaviors.NotImplemented,
    };

    return queryShim;
}

This works with simple queries, but if I add some more complexity, say an Expand operator, then everything breaks down because I have no idea what to mock or fake any more.

Example that works without the Expand lambda:

ODataClient.Microsoft.Dynamics.CRM.System _client;
IQueryable<Insurance> insurancesQuery = from i in _client.Insurances.Expand(nameof(Insurance.Account_id).ToLower()) select i;
IList<Insurance> insurances = insurancesQuery.ToList();

Result StackTrace:
at lambda_method(Closure , Ecr_insurance ) at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)

With some documentation I think the library would be much more usable in unit tests.

kornakar commented 6 years ago

I found a partial answer to this. The line ExpandString = (s) => GetDataServiceQuery(default(T)), should be ExpandString = (s) => GetDataServiceQuery(data), so that the Expand lambda can make the query and return the correct data for nested models.

I still think this is way too difficult. So any suggestions on how to improve the testing experience?

Robelind commented 5 years ago

I would also like some information regarding this.