Mam kilka testów jednostkowych, w których oczekuje się, że `` bieżący czas '' będzie inny niż DateTime.Now i oczywiście nie chcę zmieniać czasu komputera.
Jaka jest najlepsza strategia, aby to osiągnąć?
c#
unit-testing
datetime
mstest
systemtime
Pedro
źródło
źródło
DateTime
. To będzie ten, który testujesz, istniejąca metoda po prostu wywoła przeciążenie znow
.Odpowiedzi:
Najlepszą strategią jest owinąć aktualny czas w abstrakcji i wstrzyknąć tę abstrakcję do konsumenta .
Alternatywnie możesz również zdefiniować abstrakcję czasu jako kontekst otoczenia :
Umożliwi to spożywanie go w następujący sposób:
W teście jednostkowym można zamienić
TimeProvider.Current
na obiekt Test Double / Mock. Przykład przy użyciu Moq:Jednak podczas testów jednostkowych ze stanem statycznym zawsze pamiętaj, aby zburzyć urządzenie , wywołując
TimeProvider.ResetToDefault()
.źródło
DateTime.UtcNow
i podobne, ale przeglądy kodu i tak są dobrym pomysłem.To wszystko są dobre odpowiedzi, oto co zrobiłem przy innym projekcie:
Stosowanie:
Uzyskaj dzisiejszą PRAWDZIWĄ datę i godzinę
Zamiast korzystać z DateTime.Now, musisz użyć
SystemTime.Now()
... To nie jest trudna zmiana, ale to rozwiązanie może nie być idealne dla wszystkich projektów.Podróże w czasie (przejdźmy 5 lat w przyszłość)
Zdobądź naszą podróbkę „dzisiaj” (będzie za 5 lat od „dzisiaj”)
Wyzeruj datę
źródło
Mole:
Zastrzeżenie - pracuję nad Molesami
źródło
Masz kilka opcji, aby to zrobić:
Użyj mocking framework i użyj DateTimeService (zaimplementuj małą klasę opakowania i wstrzyknij ją do kodu produkcyjnego). Implementacja opakowania będzie miała dostęp do DateTime iw testach będzie można mockować klasę opakowania.
Użyj izolatora Typemock , może on sfałszować DateTime.Now i nie będzie wymagał zmiany testowanego kodu.
Używaj Moli , może również fałszować DateTime.Now i nie będzie wymagać zmian w kodzie produkcyjnym.
Kilka przykładów:
Klasa opakowania używająca Moq:
Faking DateTime bezpośrednio za pomocą Isolatora:
Zastrzeżenie - pracuję w Typemock
źródło
Dodaj fałszywy zespół dla systemu (kliknij prawym przyciskiem myszy odniesienie do systemu => Dodaj fałszywy zespół).
I napisz do swojej metody testowej:
źródło
W odniesieniu do odpowiedzi @crabcrusherclamcollector występuje problem podczas korzystania z tego podejścia w zapytaniach EF (System.NotSupportedException: typ węzła wyrażenia LINQ „Invoke” nie jest obsługiwany w LINQ to Entities). Zmodyfikowałem implementację na:
źródło
Aby przetestować kod, który zależy od
System.DateTime
,system.dll
należy wyszydzić.Są dwa znane mi ramy, które to robią. Microsoft podróbki i fartuchy .
Podróbki Microsoftu wymagają ultimatum Visual Studio 2012 i działają prosto z compton.
Smocks to open source i bardzo łatwy w użyciu. Można go pobrać za pomocą NuGet.
Poniżej przedstawiono przykład
System.DateTime
:źródło
Bezpieczne wątek
SystemClock
używającThreadLocal<T>
działa świetnie dla mnie.ThreadLocal<T>
jest dostępny w .Net Framework v4.0 i nowszych.Przykład użycia:
źródło
Now
wystąpienie.AsyncLocal
zamiastThreadLocal
Console.WriteLine(SystemClock.Now); SystemClock.Set(new DateTime(2017, 01, 01)); Console.WriteLine(SystemClock.Now); await Task.Delay(1000); Console.WriteLine(SystemClock.Now);
Napotkałem ten sam problem, ale znalazłem projekt badawczy firmy Microsoft, który rozwiązuje ten problem.
http://research.microsoft.com/en-us/projects/moles/
Moles to lekka struktura dla testowych kodów pośredniczących i objazdów w .NET, która jest oparta na delegatach. Moli można używać do obejścia dowolnej metody .NET, w tym metod niewirtualnych / statycznych w typach zamkniętych
Przykładowy kod został zmodyfikowany w stosunku do oryginału.
Zrobiłem to, co sugerowali inni, i wyodrębniłem DateTime do dostawcy. Czułem się po prostu źle i czułem, że to za dużo na samo testowanie. Dziś wieczorem wprowadzę to do mojego osobistego projektu.
źródło
Jedna uwaga specjalna na temat kpiny
DateTime.Now
z TypeMock ...Wartość
DateTime.Now
musi być umieszczona w zmiennej, aby została poprawnie wyśmiana. Na przykład:To nie działa:
Jednak to robi:
źródło
Mock Objects.
Mock DateTime, który zwraca wartość Now, która jest odpowiednia dla Twojego testu.
źródło
Dziwię się, że nikt nie zasugerował jednej z najbardziej oczywistych dróg:
Następnie możesz po prostu zastąpić tę metodę w swoim podwójnym teście.
TimeProvider
W niektórych przypadkach lubię też wstrzykiwać klasę, ale w innych jest to więcej niż wystarczające. Prawdopodobnie wolałbym tęTimeProvider
wersję, gdybyś chciał użyć jej ponownie w kilku klasach.EDYCJA: Dla każdego, kto jest zainteresowany, nazywa się to dodaniem „szwu” do klasy, czyli punktem, w którym można podłączyć się do jego zachowania, aby je zmodyfikować (do celów testowych lub w inny sposób) bez faktycznej zmiany kodu w klasie.
źródło
Dobra praktyka jest taka, gdy DateTimeProvider implementuje IDisposable.
Następnie możesz wstrzyknąć fałszywą datę i godzinę do testów jednostkowych
Zobacz przykład Przykład DateTimeProvider
źródło
Prostym sposobem na to jest wstrzyknięcie VirtualTime. Pozwala kontrolować czas. Najpierw zainstaluj VirtualTime
Pozwala to na przykład na 5-krotne przyspieszenie czasu przy wszystkich wywołaniach funkcji DateTime.Now lub UtcNow
Aby czas płynął wolniej, np. 5 razy wolniej
Aby czas się zatrzymał, rób to
Cofanie się w czasie nie jest jeszcze testowane
Oto przykładowy test:
Możesz sprawdzić więcej testów tutaj:
https://github.com/VirtualTime/VirtualTime/blob/master/VirtualTimeLib.Tests/when_virtual_time_is_used.cs
To, co daje rozszerzenie DateTime.Now.ToVirtualTime, to instancja ITime, którą przekazujesz do metody / klasy zależnej od ITime. Niektóre DateTime.Now.ToVirtualTime są konfigurowane w wybranym kontenerze DI
Oto kolejny przykład wstrzyknięcia do contrustora klasy
źródło
Używaliśmy statycznego obiektu SystemTime, ale napotkaliśmy problemy podczas wykonywania równoległych testów jednostkowych. Próbowałem użyć rozwiązania Henka van Boeijena, ale miałem problemy z odrodzonymi wątkami asynchronicznymi, skończyło się na użyciu AsyncLocal w sposób podobny do tego poniżej:
Źródło: https://gist.github.com/CraftyFella/42f459f7687b0b8b268fc311e6b4af08
źródło
Stare pytanie, ale wciąż aktualne.
Moje podejście polega na utworzeniu nowego interfejsu i klasy do zawijania
System.DateTime.Now
połączeniaTen interfejs można wstrzyknąć do dowolnej klasy, która musi pobierać aktualną datę i godzinę. W tym przykładzie mam klasę, która dodaje przedział czasu do bieżącej daty i godziny (jednostka testowalna System.DateTime.Now.Add (TimeSpan))
Można też napisać testy, aby upewnić się, że działa poprawnie. Używam NUnit i Moq, ale wystarczy każda platforma testowa
Ten wzór będzie pracować dla wszelkich funkcji, które są zależne od czynników zewnętrznych, takich jak
System.Random.Next()
,System.DateTime.Now.UtcNow
,System.Guid.NewGuid()
itpZobacz https://loadlimited.visualstudio.com/Stamina/_git/Stamina.Core, aby uzyskać dalsze przykłady lub pobierz pakiet nuget https://www.nuget.org/packages/Stamina.Core .
źródło
Możesz zmienić klasę, którą testujesz, aby używała klasy,
Func<DateTime>
która zostanie przekazana przez jej parametry konstruktora, więc kiedy tworzysz instancję klasy w prawdziwym kodzie, możesz przekazać() => DateTime.UtcNow
doFunc<DateTime>
parametru, a podczas testu możesz spędzić czas chcesz przetestować.Na przykład:
źródło
Mam ten sam problem, ale myślę, że nie powinniśmy używać rzeczy z ustawioną datą i godziną na tej samej klasie. ponieważ pewnego dnia może to doprowadzić do niewłaściwego użycia. więc korzystałem z dostawcy
Do testów, w projekcie testowym stworzyłem pomocnika, który zajmie się zadanymi rzeczami,
na kodzie
i na testach
Ale trzeba pamiętać o jednej rzeczy, czasami prawdziwy DateTime i DateTime dostawcy nie działają tak samo
Przyjąłem, że szacunek będzie maksymalny TimeSpan.FromMilliseconds (0,00002) . Ale w większości przypadków jest to jeszcze mniej
Znajdź próbkę w MockSamples
źródło
Oto moja odpowiedź na to pytanie. Łączę wzorzec „Ambient Context” z IDisposable. Możesz więc użyć DateTimeProvider.Current w swoim normalnym kodzie programu, aw teście przesłonisz zakres za pomocą instrukcji using.
Oto jak używać powyższego DateTimeProvider w ramach testu jednostkowego
źródło
Korzystając z niego
ITimeProvider
, byliśmy zmuszeni przenieść go do specjalnego wspólnego projektu, do którego należy odwołać się z pozostałych projektów. Ale to skomplikowało kontrolę zależności .Szukaliśmy
ITimeProvider
w .NET Framework. Szukaliśmy pakietu NuGet i znaleźliśmy taki, z którym nie można współpracowaćDateTimeOffset
.Wymyśliliśmy więc własne rozwiązanie, które zależy tylko od typów standardowej biblioteki. Używamy wystąpienia
Func<DateTimeOffset>
.Jak używać
Jak zarejestrować
Autofac
( Dla przyszłych redaktorów: dołącz tutaj swoje przypadki ).
Jak przeprowadzić test jednostkowy
źródło
Być może mniej profesjonalne, ale prostsze rozwiązanie mogłoby polegać na wprowadzeniu parametru DateTime w metodzie konsumenckiej.
źródło