Das ist mein Controller:
public class BlogController : Controller
{
private IDAO<Blog> _blogDAO;
private readonly ILogger<BlogController> _logger;
public BlogController(ILogger<BlogController> logger, IDAO<Blog> blogDAO)
{
this._blogDAO = blogDAO;
this._logger = logger;
}
public IActionResult Index()
{
var blogs = this._blogDAO.GetMany();
this._logger.LogInformation("Index page say hello", new object[0]);
return View(blogs);
}
}
Wie Sie sehen können, habe ich 2 Abhängigkeiten, a IDAO
und aILogger
Und dies ist meine Testklasse. Ich benutze xUnit zum Testen und Moq zum Erstellen von Mock und Stub. Ich kann DAO
einfach verspotten , aber mit dem ILogger
ich nicht weiß, was ich tun soll, übergebe ich einfach null und kommentiere den Aufruf zum Anmelden des Controllers aus beim Test ausführen. Gibt es eine Möglichkeit zu testen, aber den Logger trotzdem irgendwie zu behalten?
public class BlogControllerTest
{
[Fact]
public void Index_ReturnAViewResult_WithAListOfBlog()
{
var mockRepo = new Mock<IDAO<Blog>>();
mockRepo.Setup(repo => repo.GetMany(null)).Returns(GetListBlog());
var controller = new BlogController(null,mockRepo.Object);
var result = controller.Index();
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<IEnumerable<Blog>>(viewResult.ViewData.Model);
Assert.Equal(2, model.Count());
}
}
ILogger
. Er hat einige gute Vorschläge in seinem Blogpost und ich bin mit meiner Lösung gekommen, die die meisten Probleme in der Antwort unten zu lösen scheint .Antworten:
Verspotten Sie es einfach und jede andere Abhängigkeit:
Sie müssen wahrscheinlich das
Microsoft.Extensions.Logging.Abstractions
Paket installieren , um es verwenden zu könnenILogger<T>
.Außerdem können Sie einen echten Logger erstellen:
quelle
Eigentlich habe ich gefunden,
Microsoft.Extensions.Logging.Abstractions.NullLogger<>
was wie eine perfekte Lösung aussieht. Installieren Sie das PaketMicrosoft.Extensions.Logging.Abstractions
und folgen Sie dem Beispiel, um es zu konfigurieren und zu verwenden:und Unit Test
quelle
Verwenden Sie einen benutzerdefinierten Logger, der
ITestOutputHelper
(von xunit) zum Erfassen von Ausgaben und Protokollen verwendet. Das Folgende ist ein kleines Beispiel, das nur dasstate
in die Ausgabe schreibt .Verwenden Sie es in Ihren Unittests wie
quelle
ILogger
wird es breiter nutzbar. 2) DerBeginScope
sollte sich nicht selbst zurückgeben, da dies bedeutet, dass alle getesteten Methoden, die einen Bereich während des Laufs beginnen und beenden, den Logger entsorgen. Erstellen Sie stattdessen eine private verschachtelte "Dummy" -Klasse, dieIDisposable
eine Instanz davon implementiert und zurückgibt (und dannIDisposable
aus entferntXunitLogger
).Für .net Core 3 Antworten, die Moq verwenden
https://stackoverflow.com/a/56728528/2164198
funktionieren aufgrund einer Änderung, die im Problem TState in ILogger.Log beschrieben wurde, nicht mehr. Früher war es ein Objekt, jetzt FormattedLogValues
Zum Glück stakx eine schöne bereitgestellt Abhilfe . Also poste ich es in der Hoffnung, dass es Zeit für andere sparen kann (es hat eine Weile gedauert, um die Dinge herauszufinden):
quelle
Wenn ich meine 2 Cent addiere, ist dies eine Hilfserweiterungsmethode, die normalerweise in eine statische Hilfsklasse eingefügt wird:
Dann verwenden Sie es wie folgt:
Und natürlich können Sie es leicht erweitern, um jede Erwartung zu verspotten (z. B. Erwartung, Botschaft usw.).
quelle
ILogger
: gist.github.com/timabell/d71ae82c6f3eaa5df26b147f9d3842ebIt.Is<string>(s => s.Equals("A parameter is empty!"))
Es ist einfach, wie andere Antworten vorschlagen, Mock zu übergeben
ILogger
, aber es wird plötzlich viel problematischer zu überprüfen, ob tatsächlich Anrufe an den Logger getätigt wurden. Der Grund ist, dass die meisten Anrufe nicht zurILogger
Schnittstelle selbst gehören.Die meisten Aufrufe sind also Erweiterungsmethoden, die die einzige
Log
Methode der Schnittstelle aufrufen . Der Grund dafür ist, dass die Implementierung der Schnittstelle viel einfacher ist, wenn Sie nur eine und nicht viele Überladungen haben, die auf dieselbe Methode hinauslaufen.Der Nachteil ist natürlich, dass es plötzlich viel schwieriger ist zu überprüfen, ob ein Anruf getätigt wurde, da sich der Anruf, den Sie überprüfen sollten, stark von dem Anruf unterscheidet, den Sie getätigt haben. Es gibt verschiedene Ansätze, um dies zu umgehen, und ich habe festgestellt, dass benutzerdefinierte Erweiterungsmethoden zum Verspotten von Frameworks das Schreiben am einfachsten machen.
Hier ist ein Beispiel für eine Methode, mit der ich gearbeitet habe
NSubstitute
:Und so kann es verwendet werden:
Es sieht genau so aus, als hätten Sie die Methode direkt verwendet. Der Trick dabei ist, dass unsere Erweiterungsmethode Priorität erhält, da sie in Namespaces "näher" ist als die ursprüngliche, sodass sie stattdessen verwendet wird.
Es gibt leider nicht 100% was wir wollen, nämlich Fehlermeldungen werden nicht so gut sein, da wir nicht direkt auf eine Zeichenfolge prüfen, sondern auf ein Lambda, das die Zeichenfolge betrifft, aber 95% sind besser als nichts :) Zusätzlich Dieser Ansatz erstellt den Testcode
PS Für Moq kann man den Ansatz des Schreibens eine Erweiterungsmethode für die Verwendung ,
Mock<ILogger<T>>
das tutVerify
ähnliche Ergebnisse zu erzielen.PPS Dies funktioniert in .Net Core 3 nicht mehr. Weitere Informationen finden Sie in diesem Thread: https://github.com/nsubstitute/NSubstitute/issues/597#issuecomment-573742574
quelle
Bereits erwähnt können Sie es wie jede andere Schnittstelle verspotten.
So weit, ist es gut.
Das Schöne ist, dass Sie
Moq
damit überprüfen können , ob bestimmte Anrufe ausgeführt wurden . Zum Beispiel überprüfe ich hier, ob das Protokoll mit einem bestimmten aufgerufen wurdeException
.Wenn Sie
Verify
den Punkt verwenden, tun Sie dies gegen die realeLog
Methode von derILooger
Schnittstelle und nicht gegen die Erweiterungsmethoden.quelle
Aufbauend auf der Arbeit von @ ivan-samygin und @stakx finden Sie hier Erweiterungsmethoden, die auch mit der Ausnahme und allen Protokollwerten (KeyValuePairs) übereinstimmen können.
Diese funktionieren (auf meinem Computer;)) mit .Net Core 3, Moq 4.13.0 und Microsoft.Extensions.Logging.Abstractions 3.1.0.
quelle
Und bei Verwendung von StructureMap / Lamar:
Docs:
quelle
Das bloße Erstellen eines Dummys
ILogger
ist für Unit-Tests nicht sehr wertvoll. Sie sollten auch überprüfen, ob die Protokollierungsaufrufe getätigt wurden. Sie können ein Mock injizierenILogger
mit Moq aber den Anruf Überprüfung kann ein wenig schwierig sein. Dieser Artikel befasst sich ausführlich mit der Überprüfung mit Moq.Hier ist ein sehr einfaches Beispiel aus dem Artikel:
Es wird überprüft, ob eine Informationsnachricht protokolliert wurde. Wenn wir jedoch komplexere Informationen über die Nachricht wie die Nachrichtenvorlage und die genannten Eigenschaften überprüfen möchten, wird es schwieriger:
Ich bin mir sicher, dass Sie dasselbe mit anderen spöttischen Frameworks tun können, aber die
ILogger
Benutzeroberfläche stellt sicher, dass es schwierig ist.quelle
Ist ein noch aktueller. Einfache Protokollierung zur Ausgabe in Tests für .net Core> = 3
quelle
Verwenden Sie Telerik Just Mock , um eine verspottete Instanz des Loggers zu erstellen:
quelle
Ich habe versucht, diese Logger-Schnittstelle mit NSubstitute zu verspotten (und bin fehlgeschlagen, weil
Arg.Any<T>()
ein Typparameter erforderlich ist, den ich nicht bereitstellen kann), habe jedoch einen Testlogger (ähnlich der Antwort von @ jehof) wie folgt erstellt:Sie können einfach auf alle protokollierten Nachrichten zugreifen und alle damit verbundenen wichtigen Parameter bestätigen.
quelle