Как использовать метод Moq, который имеет необязательный аргумент в своей сигнатуре без явного указания его или использования перегрузки?
Учитывая следующий интерфейс:
public interface IFoo
{
bool Foo(string a, bool b = false);
}
Попытка издеваться над ним с помощью Moq:
var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);
дает следующую ошибку во время компиляции:
Дерево выражений может не содержать вызов или вызов, который использует необязательные аргументы
Я нашел проблему выше, поднятую как улучшение в списке ошибок Moq, и, похоже, она была назначена версии 4.5 (всякий раз, когда это возможно).
Мой вопрос: что я должен делать, учитывая, что вышеизложенное не будет исправлено в ближайшее время? Являются ли мои варианты только для того, чтобы либо явным образом устанавливать значение по умолчанию для необязательного параметра каждый раз, когда я его издеваюсь (какой вид побеждает точка указания в первую очередь), или для создания перегрузки без bool (например, что бы я сделал до С# 4)?
Или кто-нибудь может найти более умный способ преодолеть эту проблему?
Ответы
Ответ 1
Я считаю, что ваш единственный выбор прямо сейчас заключается в явном включении параметра bool
в настройку для Foo
.
Я не думаю, что это побеждает цель указания значения по умолчанию. Значение по умолчанию - это удобство для вызова кода, но я думаю, что вы должны быть явным в своих тестах. Скажем, вы можете не указывать параметр bool
. Что произойдет, если в будущем кто-то изменит значение по умолчанию b
на true
? Это приведет к неудачным испытаниям (и по праву), но их будет сложнее исправить из-за скрытого предположения, что b
false
. Явное указание параметра bool
имеет еще одно преимущество: оно улучшает читаемость ваших тестов. Кто-то, проходящий через них, быстро узнает, что есть одна функция Foo
, которая принимает два параметра. Что мои 2 цента, по крайней мере:)
Как для указания его каждый раз, когда вы издеваетесь над этим, не дублируйте код: создайте и/или инициализируйте макет в функции, чтобы у вас была только одна точка изменения. Если вы действительно этого захотите, вы можете преодолеть кажущееся короткое замыкание Moq путем дублирования параметров Foo
в этой функции инициализации:
public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
if(!b)
{
fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
}
else
{
...
}
}
Ответ 2
Только что столкнулся с этой проблемой сегодня, Moq не поддерживает этот прецедент.
Итак, кажется, что для этого случая будет достаточно переопределения метода.
public interface IFoo
{
bool Foo(string a);
bool Foo(string a, bool b);
}
Теперь доступны оба метода, и этот пример будет работать:
var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);