Полностью универсальная установка Moq с попыткой прокси класса выдает сообщение «Операции с поздним связыванием не могутC#

Место общения программистов C#
Ответить
Anonymous
 Полностью универсальная установка Moq с попыткой прокси класса выдает сообщение «Операции с поздним связыванием не могут

Сообщение Anonymous »

ПРОБЛЕМА, НУЖНО РЕШИТЬ
Я пытаюсь создать макет интерфейса ISomeService, используя библиотеку Moq, которая будет обертывать его реальную реализацию SomeService< /code>.
Сейчас я делаю это вручную следующим образом:

Код: Выделить всё

var instance = new SomeService();
var mock = new Mock();
mock.Setup(x => x.Run(It.IsAny()))
.Returns(x => instance.Run(x));
Он вызывает реальную реализацию, поэтому мои тесты более надежны, и я получаю преимущества от имитации, такой как проверка и т. д. Проблема в том, что мне приходится реализовывать ее для каждого метода и каждой службы, которую я использую, то есть не тот путь. Я стремлюсь к полностью автоматизированному решению.
ЧТО Я СДЕЛАЛ
Что у меня есть для настройки() часть

Код: Выделить всё

// (x)
var mockParameter = Expression.Parameter(typeof(T), "x");

// It.IsAny()
var isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny));
var isAny = parameters.Select(x => Expression.Call(isAnyMethod.MakeGenericMethod(x.ParameterType))).ToArray();

// x.Run(It.IsAny())
mockCall = Expression.Call(mockParameter, method, isAny);
А теперь самое интересное. Если я определю лямбду следующим образом:

Код: Выделить всё

// (x) => x.Run(It.IsAny())
var mockLambda = Expression.Lambda(mockCall, mockParameter);
Он создает LambdaExpression и не работает с определением метода Setup, для которого требуется полностью определенное выражение:

Код: Выделить всё

public ISetup Setup(Expression expression)
Я не могу вызвать программу установки напрямую, потому что не знаю тип TResult, очевидно, поэтому я прибегаю к отражению:

Код: Выделить всё

var setupMethod = typeof(Mock)
.GetMethods()
.Where(x => x.Name == nameof(mock.Setup) && x.GetParameters()[0].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func)).First()
.MakeGenericMethod(method.ReturnType);

var setupResult = setupMethod.Invoke(mock, new object[] { mockLambda });
но я получаю сообщение об ошибке

System.InvalidOperationException: 'Операции с поздним связыванием не могут выполняться над типами или методами для который содержит true.

что имеет смысл, но разочаровывает.
ЧТО Я ПОПЫТАЛ< /strong>
Я попытался привести тип результата к типу объекта

Код: Выделить всё

var converted = Expression.Convert(mockCall, typeof(object));
чтобы я мог писать

Код: Выделить всё

// (x) => (object)x.Run(It.IsAny())
var mockLambda = Expression.Lambda(converted, mockParameter);
но это также вызывает исключение

System.ArgumentException: 'Неподдерживаемое выражение: (object)x.Run( It.IsAny())'

Чтобы сделать эту работу, я добавил несколько операторов else if для типов значений, где для заданного типа результата я возвращаю определенное выражение но поддерживать и расширять это кошмар. Для классов я использую объект, и, по крайней мере, эта часть работает.
Для типов значений, определяемых пользователем, я добавил общий метод

Код: Выделить всё

void SetupUnsuportedMethod(MethodInfo methodInfo)
и пользователь должен сам добавить недостающую настройку.
ВОПРОС[/b]
Есть ли способ сделать этот код полностью универсальным? Может быть, есть лучший способ решить эту проблему? Или мне придется придерживаться этого неприятного решения?

Подробнее здесь: https://stackoverflow.com/questions/793 ... erations-c
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»