Почему я получаю исключение с сообщением "Неверная настройка для не виртуального (переопределяемого в VB) члена..."?
У меня есть unit тест, где я должен смоделировать не виртуальный метод, который возвращает тип bool
public class XmlCupboardAccess
{
public bool IsDataEntityInXmlCupboard(string dataId,
out string nameInCupboard,
out string refTypeInCupboard,
string nameTemplate = null)
{
return IsDataEntityInXmlCupboard(_theDb, dataId, out nameInCupboard, out refTypeInCupboard, nameTemplate);
}
}
Итак, у меня есть фиктивный объект класса XmlCupboardAccess
и я пытаюсь настроить макет для этого метода в моем тестовом примере, как показано ниже
[TestMethod]
Public void Test()
{
private string temp1;
private string temp2;
private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();
_xmlCupboardAccess.Setup(x => x.IsDataEntityInXmlCupboard(It.IsAny<string>(), out temp1, out temp2, It.IsAny<string>())).Returns(false);
//exception is thrown by this line of code
}
Но эта строка выдает исключение
Invalid setup on a non-virtual (overridable in VB) member:
x => x.IsDataEntityInXmlCupboard(It.IsAny<String>(), .temp1, .temp2,
It.IsAny<String>())
Любое предложение, как обойти это исключение?
Ответы
Ответ 1
Moq не может высмеять не виртуальные методы и закрытые классы. При выполнении теста с использованием макета объекта MOQ фактически создает прокси-тип в памяти, который наследуется от вашего "XmlCupboardAccess" и переопределяет поведение, которое вы настроили в методе "SetUp". И, как вы знаете, на С# вы можете переопределить что-то, только если оно отмечено как виртуальное, что не соответствует Java. Java предполагает, что каждый нестатический метод будет виртуальным по умолчанию.
Еще одна вещь, которую, я считаю, вам следует рассмотреть - это ввести интерфейс для вашего "CupboardAccess" и начать издеваться над интерфейсом. Это поможет вам разделить ваш код и получить преимущества в долгосрочной перспективе.
Наконец, существуют такие рамки, как: TypeMock и JustMock, которые работают непосредственно с IL и следовательно, могут высмеивать не виртуальные методы. Оба, однако, являются коммерческими продуктами.
Ответ 2
В качестве помощи любому, у кого была такая же проблема, как и я, я случайно набрал тип реализации вместо интерфейса, например
var mockFileBrowser = new Mock<FileBrowser>();
вместо
var mockFileBrowser = new Mock<IFileBrowser>();
Ответ 3
См.
Почему свойство, которое я хочу высмеять, должно быть виртуальным?
Возможно, вам придется написать интерфейс оболочки или пометить свойство как виртуальное/абстрактное, так как Moq создает прокси-класс, который он использует для перехвата вызовов и возвращает ваши пользовательские значения, которые вы вставляете в вызов .Returns(x)
.
Ответ 4
Вы также получите эту ошибку, если убедитесь, что вызывается метод расширения интерфейса.
Например, если вы издеваетесь:
var mockValidator = new Mock<IValidator<Foo>>();
mockValidator
.Verify(validator => validator.ValidateAndThrow(foo, null));
Вы получите то же исключение, потому что .ValidateAndThrow()
является расширением интерфейса IValidator<T>
.
public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null)...
Ответ 5
Вместо того, чтобы издеваться над конкретным классом, вы должны высмеивать интерфейс этого класса Извлечь интерфейс из класса XmlCupboardAccess
public interface IXmlCupboardAccess
{
bool IsDataEntityInXmlCupboard(string dataId, out string nameInCupboard, out string refTypeInCupboard, string nameTemplate = null);
}
И вместо
private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();
изменить на
private Mock<IXmlCupboardAccess> _xmlCupboardAccess = new Mock<IXmlCupboardAccess>();
Ответ 6
Код:
private static void RegisterServices(IKernel kernel)
{
Mock<IProductRepository> mock=new Mock<IProductRepository>();
mock.Setup(x => x.Products).Returns(new List<Product>
{
new Product {Name = "Football", Price = 23},
new Product {Name = "Surf board", Price = 179},
new Product {Name = "Running shose", Price = 95}
});
kernel.Bind<IProductRepository>().ToConstant(mock.Object);
}
но см. исключение.