Mam test jednostkowy, w którym muszę mockować metodę niewirtualną, która zwraca typ 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);
}
}
Mam więc pozorowany obiekt XmlCupboardAccess
klasy i próbuję skonfigurować makietę dla tej metody w moim przypadku testowym, jak pokazano poniżej
[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
}
Ale ta linia rzuca wyjątek
Invalid setup on a non-virtual (overridable in VB) member:
x => x.IsDataEntityInXmlCupboard(It.IsAny<String>(), .temp1, .temp2,
It.IsAny<String>())
Jakieś sugestie, jak obejść ten wyjątek?
c#
unit-testing
moq
Rahul Lodha
źródło
źródło
XmlCupboardAccess
?virtual
. Moq nie może kpić z konkretnego typu, którego nie może zastąpić.Odpowiedzi:
Moq nie może mockować niewirtualnych metod i klas zapieczętowanych. Podczas wykonywania testu przy użyciu pozorowanego obiektu, MOQ faktycznie tworzy w pamięci typ proxy, który dziedziczy po twoim „XmlCupboardAccess” i przesłania zachowania, które ustawiłeś w metodzie „SetUp”. Jak wiesz w C #, możesz przesłonić coś tylko wtedy, gdy jest oznaczone jako wirtualne, co nie ma miejsca w przypadku Javy. Java zakłada, że każda metoda niestatyczna jest domyślnie wirtualna.
Inną rzeczą, którą uważam, że powinieneś rozważyć, jest wprowadzenie interfejsu dla twojego "CupboardAccess" i zamiast tego zacząć kpić z interfejsu. Pomogłoby to oddzielić kod i przyniosłoby korzyści w dłuższej perspektywie.
Wreszcie istnieją frameworki, takie jak: TypeMock i JustMock, które działają bezpośrednio z IL i dlatego mogą mockować metody niewirtualne. Oba są jednak produktami komercyjnymi.
źródło
Jako pomoc każdemu, kto miał ten sam problem co ja, przypadkowo błędnie wpisałem typ implementacji zamiast interfejsu np
zamiast
źródło
Zapoznaj się z tematem Dlaczego nieruchomość, którą chcę wyszydzić, musi być wirtualna?
Może być konieczne napisanie interfejsu opakowania lub oznaczenie właściwości jako wirtualnej / abstrakcyjnej, ponieważ Moq tworzy klasę proxy, której używa do przechwytywania wywołań i zwracania niestandardowych wartości, które umieściłeś w
.Returns(x)
wywołaniu.źródło
Zamiast kpić z konkretnej klasy, powinieneś kpić z tego interfejsu klasy. Wyodrębnij interfejs z klasy XmlCupboardAccess
A zamiast tego
zmień na
źródło
Otrzymasz ten błąd również, jeśli sprawdzasz, czy wywoływana jest metoda rozszerzenia interfejsu.
Na przykład, jeśli kpisz:
Otrzymasz ten sam wyjątek, ponieważ
.ValidateAndThrow()
jest to rozszerzenieIValidator<T>
interfejsu.public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null)...
źródło
Kod:
ale zobacz wyjątek.
źródło