it-swarm.com.de

Warum erhalte ich eine Ausnahme mit der Meldung "Ungültiges Setup für ein nicht virtuelles Mitglied (in VB überschreibbar) ..."?

Ich habe einen Unit-Test, bei dem ich eine nicht-virtuelle Methode verspotten muss, die einen Bool-Typ zurückgibt

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);
    }
}

Ich habe also ein Mock-Objekt der XmlCupboardAccess-Klasse und versuche, in diesem Testfall ein Mock für diese Methode einzurichten, wie unten gezeigt

[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
}

Aber diese Zeile löst eine Ausnahme aus 

Invalid setup on a non-virtual (overridable in VB) member: 
x => x.IsDataEntityInXmlCupboard(It.IsAny<String>(), .temp1, .temp2, 
It.IsAny<String>())

Gibt es einen Vorschlag, wie Sie diese Ausnahme umgehen können?

135
Rahul Lodha

Moq kann nicht-virtuelle Methoden und versiegelte Klassen nicht simulieren. Beim Ausführen eines Tests mit einem Scheinobjekt erstellt MOQ tatsächlich einen In-Memory-Proxy-Typ, der von Ihrem "XmlCupboardAccess" erbt und das Verhalten überschreibt, das Sie in der "SetUp" -Methode festgelegt haben. Und wie Sie in C # wissen, können Sie etwas nur überschreiben, wenn es als virtuell markiert ist, was bei Java nicht der Fall ist. Java geht davon aus, dass jede nicht statische Methode standardmäßig virtuell ist.

Ich denke, Sie sollten in Betracht ziehen, eine Schnittstelle für Ihren "CupboardAccess" einzuführen und stattdessen die Schnittstelle zu verspotten. Es würde Ihnen helfen, Ihren Code zu entkoppeln und auf längere Sicht Vorteile zu haben.

Schließlich gibt es Frameworks wie: TypeMock und JustMock , die direkt mit der IL arbeiten und daher nicht-virtuelle Methoden simulieren können. Beide sind jedoch kommerzielle Produkte.

223
Amol

Als Hilfe für alle, die das gleiche Problem wie ich hatten, habe ich versehentlich den Implementierungstyp anstelle der Schnittstelle falsch eingegeben, z.

var mockFileBrowser = new Mock<FileBrowser>();

anstatt

var mockFileBrowser = new Mock<IFileBrowser>();
7
Ralt

Bitte sehen Warum muss die Eigenschaft, die ich verspotten möchte, virtuell sein?

Möglicherweise müssen Sie eine Wrapper-Schnittstelle schreiben oder die Eigenschaft als virtuell/abstrakt markieren, da Moq eine Proxy-Klasse erstellt, mit der Aufrufe abgefangen und Ihre benutzerdefinierten Werte zurückgegeben werden, die Sie in den Aufruf .Returns(x) eingeben.

4
Bryida

Diese Fehlermeldung wird auch angezeigt, wenn Sie überprüfen, ob eine Erweiterungsmethode einer Schnittstelle aufgerufen wird.

Zum Beispiel, wenn Sie verspotten:

var mockValidator = new Mock<IValidator<Foo>>();
mockValidator
  .Verify(validator => validator.ValidateAndThrow(foo, null));

Sie erhalten dieselbe Ausnahme, da .ValidateAndThrow() eine Erweiterung der Schnittstelle IValidator<T> Ist.

public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null)...

1
Scotty.NET

Anstatt die konkrete Klasse zu verspotten, sollten Sie die Klassenschnittstelle . Aus der Klasse XmlCupboardAccess extrahieren 

public interface IXmlCupboardAccess
{
    bool IsDataEntityInXmlCupboard(string dataId, out string nameInCupboard, out string refTypeInCupboard, string nameTemplate = null);
}

Und statt

private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();

ändern 

private Mock<IXmlCupboardAccess> _xmlCupboardAccess = new Mock<IXmlCupboardAccess>();
0
Sashus