To jest mój kontroler:
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);
}
}
Jak widać, mam 2 zależności, a IDAO
i aILogger
I to jest moja klasa testowa, używam xUnit do testowania i Moq do tworzenia mock i stub, mogę DAO
łatwo kpić , ale z ILogger
nie wiem co zrobić, więc po prostu przekazuję null i komentuję wywołanie, aby zalogować się do kontrolera po uruchomieniu testu. Czy jest sposób, aby przetestować, ale nadal jakoś zachować rejestrator?
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
. Na swoim blogu ma kilka dobrych sugestii, a ja przedstawiłem moje rozwiązanie, które wydaje się rozwiązywać większość problemów opisanych poniżej .Odpowiedzi:
Po prostu kpij z tego, jak również z każdej innej zależności:
Prawdopodobnie będziesz musiał zainstalować
Microsoft.Extensions.Logging.Abstractions
pakiet, aby go używaćILogger<T>
.Ponadto możesz stworzyć prawdziwy rejestrator:
źródło
Właściwie znalazłem,
Microsoft.Extensions.Logging.Abstractions.NullLogger<>
które wygląda na idealne rozwiązanie. Zainstaluj pakietMicrosoft.Extensions.Logging.Abstractions
, a następnie postępuj zgodnie z przykładem, aby go skonfigurować i używać:i test jednostkowy
źródło
Użyj niestandardowego programu rejestrującego, który używa
ITestOutputHelper
(z xunit) do przechwytywania danych wyjściowych i dzienników. Poniżej znajduje się mały przykład, który zapisuje tylkostate
dane wyjściowe.Użyj go w swoich publikacjach, takich jak
źródło
ILogger
zwiększy jego użyteczność. 2) NieBeginScope
powinien zwracać się sam, ponieważ oznacza to, że każda przetestowana metoda, która rozpoczyna i kończy zakres podczas wykonywania, pozbędzie się rejestratora. Zamiast tego utwórz prywatną „fałszywą” klasę zagnieżdżoną, która implementujeIDisposable
i zwraca jej instancję (a następnie usuwaIDisposable
zXunitLogger
).Dla odpowiedzi .net core 3, które używają Moq
https://stackoverflow.com/a/56728528/2164198
nie działają już z powodu zmiany opisanej w problemie TState w ILogger.Log, który był wcześniej obiektem, teraz FormattedLogValues
Na szczęście firma stakx zapewniła dobre obejście . Dlatego publikuję to z nadzieją, że pozwoli to zaoszczędzić czas innym (zajęło to trochę czasu, zanim to zrozumiał):
źródło
Dodając moje 2 centy, jest to metoda rozszerzenia pomocnika, zwykle umieszczana w statycznej klasie pomocniczej:
Następnie używasz tego w ten sposób:
Oczywiście możesz go łatwo rozszerzyć, aby udawać wszelkie oczekiwania (np. Oczekiwanie, wiadomość itp.)
źródło
ILogger
: gist.github.com/timabell/d71ae82c6f3eaa5df26b147f9d3842ebIt.Is<string>(s => s.Equals("A parameter is empty!"))
Jest to łatwe, jak sugerują inne odpowiedzi, aby przejść próbę
ILogger
, ale nagle znacznie bardziej problematyczne staje się zweryfikowanie, czy rzeczywiście wykonano połączenia z rejestratorem. Powodem jest to, że większość wywołań w rzeczywistości nie należy do samegoILogger
interfejsu.Dlatego większość wywołań to metody rozszerzające, które wywołują jedyną
Log
metodę interfejsu. Wydaje się, że łatwiej jest wykonać implementację interfejsu, jeśli masz tylko jedno i niewiele przeciążeń, które sprowadzają się do tej samej metody.Wadą jest oczywiście to, że nagle znacznie trudniej jest sprawdzić, czy połączenie zostało wykonane, ponieważ połączenie, które należy zweryfikować, bardzo różni się od połączenia, które wykonałeś. Istnieje kilka różnych podejść do obejścia tego problemu i odkryłem, że niestandardowe metody rozszerzeń do mockowania frameworka ułatwiają pisanie.
Oto przykład metody, którą stworzyłem do pracy
NSubstitute
:A tak można to wykorzystać:
Wygląda dokładnie tak, jakbyś użył tej metody bezpośrednio. Sztuczka polega na tym, że nasza metoda rozszerzająca ma priorytet, ponieważ jest „bliżej” przestrzeni nazw niż oryginalna, więc zostanie użyta zamiast niej.
Nie daje niestety 100% tego, czego chcemy, a mianowicie komunikaty o błędach nie będą tak dobre, ponieważ nie sprawdzamy bezpośrednio na łańcuchu, a raczej na lambdzie, która zawiera ciąg, ale 95% jest lepsze niż nic :) Dodatkowo takie podejście stworzy kod testowy
PS W przypadku Moq można zastosować podejście polegające na napisaniu metody rozszerzającej
Mock<ILogger<T>>
,Verify
aby osiągnąć podobne wyniki.PPS To już nie działa w .Net Core 3, sprawdź ten wątek, aby uzyskać więcej informacji: https://github.com/nsubstitute/NSubstitute/issues/597#issuecomment-573742574
źródło
Już wspomniałem, że możesz go kpić jak każdy inny interfejs.
Na razie w porządku.
Fajną rzeczą jest to, że możesz użyć
Moq
do sprawdzenia, czy niektóre połączenia zostały wykonane . Na przykład tutaj sprawdzam, czy dziennik został wywołany z określonymException
.Przy używaniu
Verify
chodzi o zrobienie tego w stosunku do rzeczywistejLog
metody zILooger
interfejsu, a nie metod rozszerzających.źródło
Opierając się jeszcze bardziej na pracy @ ivan-samygin i @stakx, oto metody rozszerzające, które mogą również pasować do wyjątku i wszystkich wartości dziennika (KeyValuePairs).
Działają (na moim komputerze;)) z .Net Core 3, Moq 4.13.0 i Microsoft.Extensions.Logging.Abstractions 3.1.0.
źródło
A korzystając ze StructureMap / Lamar:
Dokumenty:
źródło
Samo utworzenie atrapy
ILogger
nie jest zbyt wartościowe w przypadku testów jednostkowych. Powinieneś także sprawdzić, czy wykonano wywołania logowania. Możesz wstrzyknąć próbę zaILogger
pomocą Moq, ale weryfikacja połączenia może być trochę trudna. Ten artykuł zawiera szczegółowe informacje na temat weryfikacji za pomocą Moq.Oto bardzo prosty przykład z artykułu:
Sprawdza, czy została zarejestrowana wiadomość informacyjna. Ale jeśli chcemy zweryfikować bardziej złożone informacje o wiadomości, takie jak szablon wiadomości i nazwane właściwości, staje się to trudniejsze:
Jestem pewien, że możesz zrobić to samo z innymi frameworkami do mockowania, ale
ILogger
interfejs zapewnia, że jest to trudne.źródło
Jeśli nadal aktualny. Prosty sposób na logowanie do wyników testów dla .net core> = 3
źródło
Użyj Telerik Just Mock, aby utworzyć fałszywą instancję programu rejestrującego:
źródło
Próbowałem kpić z tego interfejsu Loggera za pomocą NSubstitute (i nie powiodło się, ponieważ
Arg.Any<T>()
wymaga parametru typu, którego nie mogę podać), ale skończyło się na utworzeniu rejestratora testu (podobnie do odpowiedzi @ jehof) w następujący sposób:Możesz łatwo uzyskać dostęp do wszystkich zarejestrowanych wiadomości i potwierdzić wszystkie istotne parametry, które są z nimi dostarczane.
źródło