EntityFramework-Plus icon indicating copy to clipboard operation
EntityFramework-Plus copied to clipboard

Exception when unit testing code where the Future method is used

Open ghost opened this issue 8 years ago • 7 comments

When I execute a unit test on code that uses the Future() method it will throw an exception:

Oops! A general error has occurred. Please report the issue including the stack trace to our support team: [email protected]

at Z.EntityFramework.Plus.InternalExtensions.GetObjectQuery[T](IQueryable1 query) at Z.EntityFramework.Plus.QueryFutureExtensions.Future[T](IQueryable1 query) at Domain.Service.GlobalSearchService.<Search>d__5.MoveNext() in D:\Projects\Main\Projects\Domain\Service\GlobalSearchService.cs:line 30

ghost avatar Mar 08 '17 12:03 ghost

There is solution for EntityFramework.Extended. You can found it here: https://github.com/zzzprojects/EntityFramework.Extended/issues/129 However, approach of wrapping Future() method is not achievable with EntityFramework-Plus. ToObjectQuery method is internal now. Why it is so?

tomaspakala avatar Jul 20 '17 16:07 tomaspakala

Hello @tomaspakala ,

EntityFramework.Extended and EntityFramework.Plus is not the same library, so that's normal there is some difference.

When the V2 will be under development, we will make sure to try to release some utilities like this one method public.

Best Regards,

Jonathan

JonathanMagnan avatar Jul 20 '17 18:07 JonathanMagnan

@JonathanMagnan are there any updates about making the utility method GetObjectQuery() public?

aschiffmann avatar Mar 22 '19 15:03 aschiffmann

Hello @aschiffmann ,

We will look this week if there is any reason why we don't want this method public yet!

In 1-2 months, we will more globally check which helper method should be made public in https://entityframework-classic.net/, then we will probably make the same change in this library.

JonathanMagnan avatar Mar 23 '19 13:03 JonathanMagnan

Hello @aschiffmann ,

The v1.8.25 has been released

The extension methods GetObjectQuery is now public. We are not ready yet to make a utilities section for EF Classic, so we choose to just make it public here meanwhile.

JonathanMagnan avatar Apr 10 '19 11:04 JonathanMagnan

@aschiffmann @JonathanMagnan Something i came up with last month after an epiphany. It will allow you to mock a Future object for return from a mocked repository call.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Z.EntityFramework.Plus;

namespace TestFutureHelper
{
    public static class TestFutureHelper<T> where T : class
    {
        public static QueryFutureValue<T> GetFutureValue(T data)
        {

            var context = GetInMemoryDbContext<TestContext<T>>();
            context.Add(data);
            context.SaveChanges();

            return context.TestData.FutureValue();
        }

        public static QueryFutureEnumerable<T> GetFutureEnumerable(IEnumerable<T> data)
        {
            var context = GetInMemoryDbContext<TestContext<T>>();
            context.AddRange(data);
            context.SaveChanges();

            return context.TestData.Future();
        }

        private static TContext GetInMemoryDbContext<TContext>() where TContext : DbContext
        {
            var optionsBuilder = new DbContextOptionsBuilder<TContext>();

            var guid = Guid.NewGuid().ToString();

            optionsBuilder.UseInMemoryDatabase(databaseName: guid)
                .ConfigureWarnings(w =>                    w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.InMemoryEventId.TransactionIgnoredWarning))
                .EnableSensitiveDataLogging();

            var context = (TContext)Activator.CreateInstance(typeof(TContext), optionsBuilder.Options);
            BatchDeleteManager.InMemoryDbContextFactory = () => context;
            BatchUpdateManager.InMemoryDbContextFactory = () => context;

            return context;
        }

        private class TestContext<T> : DbContext where T : class
        {
            public TestContext(DbContextOptions<TestContext<T>> options) : base(options)
            {
            }
            public DbSet<T> TestData { get; set; }
        }
    }
}

unit tests

        [Test]
        public void TestFutureValue()
        {
            var expected = new TestObject();

            QueryFutureValue<TestObject> value = null;
            Assert.DoesNotThrow(() => value = TestFutureHelper<TestObject>.GetFutureValue(expected));

            Assert.IsNotNull(value);
            TestObject ret = null;
            Assert.DoesNotThrow(() => ret= value.Value);
            Assert.AreEqual(expected, ret);
        }

        [Test]
        public void TestFutureEnumerable()
        {
            var expected = new TestObject();

            QueryFutureEnumerable<TestObject> enumerable = null;
            Assert.DoesNotThrow(() => enumerable = TestFutureHelper<TestObject>.GetFutureEnumerable(new List<TestObject>{expected}));

            Assert.IsNotNull(enumerable);
            List<TestObject> ret = null;
            Assert.DoesNotThrow(() => ret = enumerable.ToList());
            Assert.AreEqual(expected, ret[0]);
        }

        private class TestObject
        {
            [Key]
            public int Id { get; set; }
            public string Test { get; set; }
        }

ksmithRenweb avatar Apr 11 '19 15:04 ksmithRenweb

@JonathanMagnan I' trying to mock QueryFutureEnumerable object with autofixture something like var foo = fixture.Create<QueryFutureEnumerable<long>>() , But I'm getting the following error,

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
System.ArgumentException: Format of the initialization string does not conform to specification starting at index 0.

arj060892 avatar Feb 17 '22 18:02 arj060892