EF Динамическая проекция проваливает тесты с Moq - PullRequest
0 голосов
/ 13 сентября 2018

Я пишу модульные тесты для своего сервиса, который общается с базой данных, используя Entity Framework в качестве ORM. В моем сервисе есть фрагмент кода, который динамически проецируется на таблицу для выбора объекта анонимного типа, как показано ниже -

string selectQuery = "new ( " + string.Join(",", someColumns) + ")";
var values = await context.MyTable.Where(data => data.Id == someId).Select(selectQuery).ToListAsync();

Это так, потому что проецируемые мной столбцы неизвестны во время компиляции и могут изменяться при определенных условиях. Рабочий код работает, как и ожидалось, используя код выше.

Однако при запуске теста он начинает выдавать System.ArgumentException со следующим сообщением -

Выражение типа 'System.Collections.Generic.IEnumerable & # x60; 1 [DynamicClass1]' нельзя использовать для типа возвращаемого значения 'System.Collections.Generic.IEnumerable & # x60; 1 [MyTable]'

Ниже приведен мой тест -

var values = new List<MyTable>
        {
            new MyTable
            {
                Id = 1,
                Column1 = value1,
                Column2 = value2,
                Column3 = value3,
                Column4 = value4
            },
            new MyTable
            {
                Id = 2,
                Column1 = value5,
                Column2 = value6,
                Column3 = value7,
                Column4 = value8             
            }
        }.AsQueryable();


var mockValues = new Mock<DbSet<MyTable>>();

mockValues.As<IDbAsyncEnumerable<T>>()
            .Setup(m => m.GetAsyncEnumerator())
            .Returns(new TestDbAsyncEnumerator<T>(values.GetEnumerator()));

        mockValues.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<T>(values.Provider));
        mockValues.As<IQueryable<T>>().Setup(m => m.Expression).Returns(values.Expression);
        mockValues.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(values.ElementType);
        mockValues.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(values.GetEnumerator());

Mock<Context> contextMock = new Mock<Context>();
contextMock.Setup(x => x.MyTable).Returns(mockValues.Object);

var result = await _myService.SomeMethod(contextMock.Object, ...);
Assert.IsTrue(result);

Я сослался на Документацию Microsoft для поддержки async для моего теста.

Глядя на исключение, я догадался, что это должно быть связано с динамической проекцией, которую я здесь использую, поэтому я изменил код в сервисе на ниже -

var values = await context.MyTable.Where(data => data.Id == someId).Select(x => new { x.Id, x.Column1, x.Column2, x.Column4 }).ToListAsync();

, который в основном удаляет динамическую конструкцию и, как я ожидал, сработал.

Итак, вопрос в том, есть ли способ динамически проецировать столбцы и при этом работать мои тесты.

...