@ Pure.Krome: gute Antwort, aber ich werde ein paar Details hinzufügen
@ Kevin: Sie müssen eine Lösung auswählen, abhängig von den Änderungen, die Sie am Code vornehmen können.
Wenn Sie es ändern können, macht eine Abhängigkeitsinjektion den Code testbarer. Wenn Sie nicht können, brauchen Sie eine gute Isolation.
Mit dem kostenlosen Mocking-Framework (Moq, RhinoMocks, NMock ...) können Sie nur Delegierte, Schnittstellen und virtuelle Methoden verspotten. Für statische, versiegelte und nicht virtuelle Methoden haben Sie also drei Lösungen:
- TypeMock Isolator (kann alles verspotten, ist aber teuer)
- JustMock von Telerik ( Neuankömmling, günstiger , aber immer noch nicht kostenlos)
- Maulwürfe von Microsoft (die einzige kostenlose Lösung zur Isolierung)
Ich empfehle Moles , weil es kostenlos und effizient ist und Lambda-Ausdrücke wie Moq verwendet. Nur ein wichtiges Detail: Maulwürfe liefern Stummel, keine Verspottungen. Sie können Moq also weiterhin für Schnittstellen und Delegaten verwenden;)
Mock: Eine Klasse, die eine Schnittstelle implementiert und die Möglichkeit bietet, die Werte für die Rückgabe / Ausnahmen für bestimmte Methoden dynamisch festzulegen und zu überprüfen, ob bestimmte Methoden aufgerufen / nicht aufgerufen wurden.
Stub: Wie eine Scheinklasse, nur dass sie nicht die Möglichkeit bietet, zu überprüfen, ob Methoden aufgerufen / nicht aufgerufen wurden.
In .NET besteht die Möglichkeit, MOQ und andere Verspottungsbibliotheken auszuschließen. Sie müssen mit der rechten Maustaste auf den Lösungs-Explorer für eine Assembly klicken, die eine statische Methode enthält, die Sie verspotten möchten, und " Gefälschte Assembly hinzufügen" auswählen . Als nächstes können Sie die statischen Assembly-Methoden frei verspotten.
Angenommen, Sie möchten die
System.DateTime.Now
statische Methode verspotten . Tun Sie dies zum Beispiel so:using (ShimsContext.Create()) { System.Fakes.ShimDateTime.NowGet = () => new DateTime(1837, 1, 1); Assert.AreEqual(DateTime.Now.Year, 1837); }
Sie haben ähnliche Eigenschaften für jede statische Eigenschaft und Methode.
quelle
Sie können dies mit der Pose- Bibliothek erreichen, die bei nuget erhältlich ist. Sie können sich unter anderem über statische Methoden lustig machen. Schreiben Sie in Ihre Testmethode Folgendes:
Shim shim = Shim.Replace(() => StaticClass.GetFile(Is.A<string>())) .With((string name) => /*Here return your mocked value for test*/); var sut = new Service(); PoseContext.Isolate(() => result = sut.foo("filename") /*Here the foo will take your mocked implementation of GetFile*/, shim);
Weitere Informationen finden Sie hier https://medium.com/@tonerdo/unit-testing-datetime-now-in-c-without-using-interfaces-978d372478e8
quelle
Ich mochte Pose, konnte aber nicht aufhören, InvalidProgramException auszulösen, was ein bekanntes Problem zu sein scheint . Jetzt benutze ich Kittel wie folgt :
Smock.Run(context => { context.Setup(() => DateTime.Now).Returns(new DateTime(2000, 1, 1)); // Outputs "2000" Console.WriteLine(DateTime.Now.Year); });
quelle
Ich habe mit dem Konzept herumgespielt, die statischen Methoden zu überarbeiten, um einen Delegaten aufzurufen, den Sie zu Testzwecken extern festlegen können.
Dies würde kein Testframework verwenden und wäre eine vollständig maßgeschneiderte Lösung. Der Refactor hat jedoch keinen Einfluss auf die Signatur Ihres Anrufers und wäre daher relativ sicher.
Damit dies funktioniert, müssen Sie Zugriff auf die statische Methode haben, damit sie für externe Bibliotheken wie z
System.DateTime
.Hier ist ein Beispiel, mit dem ich gespielt habe, wo ich einige statische Methoden erstellt habe, eine mit einem Rückgabetyp, der zwei Parameter akzeptiert, und eine generische, die keinen Rückgabetyp hat.
Die statische Hauptklasse:
public static class LegacyStaticClass { // A static constructor sets up all the delegates so production keeps working as usual static LegacyStaticClass() { ResetDelegates(); } public static void ResetDelegates() { // All the logic that used to be in the body of the static method goes into the delegates instead. ThrowMeDelegate = input => throw input; SumDelegate = (a, b) => a + b; } public static Action<Exception> ThrowMeDelegate; public static Func<int, int, int> SumDelegate; public static void ThrowMe<TException>() where TException : Exception, new() => ThrowMeDelegate(new TException()); public static int Sum(int a, int b) => SumDelegate(a, b); }
Die Unit-Tests (xUnit und Shouldly)
public class Class1Tests : IDisposable { [Fact] public void ThrowMe_NoMocking_Throws() { Should.Throw<Exception>(() => LegacyStaticClass.ThrowMe<Exception>()); } [Fact] public void ThrowMe_EmptyMocking_DoesNotThrow() { LegacyStaticClass.ThrowMeDelegate = input => { }; LegacyStaticClass.ThrowMe<Exception>(); true.ShouldBeTrue(); } [Fact] public void Sum_NoMocking_AddsValues() { LegacyStaticClass.Sum(5, 6).ShouldBe(11); } [Fact] public void Sum_MockingReturnValue_ReturnsMockedValue() { LegacyStaticClass.SumDelegate = (a, b) => 6; LegacyStaticClass.Sum(5, 6).ShouldBe(6); } public void Dispose() { LegacyStaticClass.ResetDelegates(); } }
quelle