Próbuję przetestować jednostkę do aparatu zarządzania hostami WCF, który napisałem. Silnik zasadniczo tworzy wystąpienia ServiceHost w locie na podstawie konfiguracji. Dzięki temu możemy dynamicznie zmieniać konfigurację dostępnych usług bez konieczności wyłączania ich wszystkich i ponownego uruchamiania za każdym razem, gdy dodawana jest nowa usługa lub usuwana jest stara.
Mam jednak trudności z testowaniem jednostkowym tego silnika zarządzania hostem ze względu na sposób działania ServiceHost. Jeśli ServiceHost został już utworzony, otwarty i jeszcze nie zamknięty dla określonego punktu końcowego, nie można utworzyć innego ServiceHost dla tego samego punktu końcowego, co powoduje wyjątek. Ze względu na fakt, że nowoczesne platformy testów jednostkowych równolegle wykonują swoje testy, nie mam skutecznego sposobu na testowanie jednostkowe tego fragmentu kodu.
Korzystałem z xUnit.NET, mając nadzieję, że ze względu na jego rozszerzalność uda mi się znaleźć sposób, aby zmusić go do seryjnego uruchamiania testów. Jednak nie miałem szczęścia. Mam nadzieję, że ktoś tutaj na SO napotkał podobny problem i wie, jak sprawić, aby testy jednostkowe były uruchamiane seryjnie.
UWAGA: ServiceHost to klasa WCF napisana przez firmę Microsoft. Nie mam możliwości zmiany tego zachowania. Hostowanie każdego punktu końcowego usługi tylko raz jest również właściwym zachowaniem ... jednak nie jest szczególnie sprzyjające testom jednostkowym.
źródło
TestServer
w dockerze. Musiałem więc serializować testy integracyjne.Odpowiedzi:
Każda klasa testowa jest unikatową kolekcją testów, a testy w jej ramach będą uruchamiane sekwencyjnie, więc jeśli umieścisz wszystkie testy w tej samej kolekcji, będą one uruchamiane sekwencyjnie.
W xUnit możesz wprowadzić następujące zmiany, aby to osiągnąć:
Równolegle będą działać:
namespace IntegrationTests { public class Class1 { [Fact] public void Test1() { Console.WriteLine("Test1 called"); } [Fact] public void Test2() { Console.WriteLine("Test2 called"); } } public class Class2 { [Fact] public void Test3() { Console.WriteLine("Test3 called"); } [Fact] public void Test4() { Console.WriteLine("Test4 called"); } } }
Aby uczynić go sekwencyjnym, wystarczy umieścić obie klasy testowe w tej samej kolekcji:
namespace IntegrationTests { [Collection("Sequential")] public class Class1 { [Fact] public void Test1() { Console.WriteLine("Test1 called"); } [Fact] public void Test2() { Console.WriteLine("Test2 called"); } } [Collection("Sequential")] public class Class2 { [Fact] public void Test3() { Console.WriteLine("Test3 called"); } [Fact] public void Test4() { Console.WriteLine("Test4 called"); } } }
Więcej informacji można znaleźć pod tym linkiem
źródło
Ważne: ta odpowiedź dotyczy .NET Framework. Aby uzyskać dotnet core, zobacz odpowiedź Dimitry'ego dotyczącą
xunit.runner.json
.Wszystkie dobre testy jednostkowe powinny być izolowane w 100%. Używanie stanu wspólnego (np. W zależności od
static
właściwości modyfikowanej przez każdy test) jest uważane za złą praktykę.To powiedziawszy, Twoje pytanie dotyczące uruchamiania testów xUnit w kolejności ma odpowiedź! Napotkałem dokładnie ten sam problem, ponieważ mój system używa statycznego lokalizatora usług (który jest mniej niż idealny).
Domyślnie xUnit 2.x uruchamia wszystkie testy równolegle. Można to zmodyfikować dla każdego zestawu, definiując
CollectionBehavior
w swoim AssemblyInfo.cs w projekcie testowym.W przypadku separacji na zespół użyj:
using Xunit; [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
lub w przypadku całkowitego braku zrównoleglania:
[assembly: CollectionBehavior(DisableTestParallelization = true)]
Ten ostatni jest prawdopodobnie tym, którego chcesz. Więcej informacji na temat zrównoleglania i konfiguracji można znaleźć w dokumentacji xUnit .
źródło
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerClass, DisableTestParallelization = true)]
. Dzięki tobie @Squiggle mogę przeprowadzić wszystkie testy i pójść na kawę! :)W przypadku projektów .NET Core utwórz za
xunit.runner.json
pomocą:{ "parallelizeAssembly": false, "parallelizeTestCollections": false }
Należy również pamiętać,
csproj
powinna zawierać<ItemGroup> <None Update="xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>
W przypadku starych projektów .Net Core
project.json
powinieneś zawierać"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
źródło
<ItemGroup><None Include="xunit.runner.json" CopyToOutputDirectory="Always" /></ItemGroup>
lub podobny?<ItemGroup> <None Update="xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>
dotnet test --no-build -c Release -- xunit.parallelizeTestCollections=false
ale nie zadziałało.W przypadku projektów .NET Core można skonfigurować xUnit za pomocą
xunit.runner.json
pliku, zgodnie z dokumentacją pod adresem https://xunit.github.io/docs/configuring-with-json.html .Ustawienie, które należy zmienić, aby zatrzymać równoległe wykonywanie testów, to
parallelizeTestCollections
domyślnietrue
:Tak
xunit.runner.json
wygląda minimum do tego celu{ "parallelizeTestCollections": false }
Jak wspomniano w dokumentacji, pamiętaj, aby dołączyć ten plik do swojej kompilacji:
Dodawanie
<Content Include=".\xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content>
do swojego
.csproj
pliku lubDodawanie
"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
do twojego
project.json
plikuw zależności od rodzaju projektu.
Na koniec, oprócz powyższego, jeśli używasz programu Visual Studio, upewnij się, że przypadkowo nie kliknąłeś przycisku Uruchom testy równolegle , co spowoduje równoległe uruchamianie testów, nawet jeśli wyłączyłeś równoległość w
xunit.runner.json
. Projektanci interfejsu użytkownika Microsoftu sprytnie sprawili, że ten przycisk nie został oznaczony, był trudny do zauważenia i około centymetra od przycisku „Uruchom wszystko” w Eksploratorze testów, aby zmaksymalizować szansę, że trafisz go przez pomyłkę i nie masz pojęcia, dlaczego testy nagle zawodzą:źródło
xunit.runner.json
pliku? A co maxunit.runner.json
wspólnego określenie , czy testy są uruchamiane seryjnie?To stare pytanie, ale chciałem napisać rozwiązanie dla osób szukających nowych, takich jak ja :)
Uwaga: używam tej metody w testach integracji Dot Net Core WebUI z xunit w wersji 2.4.1.
Utwórz pustą klasę o nazwie NonParallelCollectionDefinitionClass, a następnie nadaj tej klasie atrybut CollectionDefinition, jak poniżej. (Ważną częścią jest DisableParallelization = ustawienie true).
using Xunit; namespace WebUI.IntegrationTests.Common { [CollectionDefinition("Non-Parallel Collection", DisableParallelization = true)] public class NonParallelCollectionDefinitionClass { } }
Następnie dodaj atrybut Collection do klasy, której nie chcesz, aby działała równolegle, jak poniżej. (Ważną częścią jest nazwa kolekcji. Musi być taka sama jak nazwa użyta w CollectionDefinition)
namespace WebUI.IntegrationTests.Controllers.Users { [Collection("Non-Parallel Collection")] public class ChangePassword : IClassFixture<CustomWebApplicationFactory<Startup>> ...
Kiedy to robimy, najpierw uruchamiane są inne testy równoległe. Następnie uruchamiane są inne testy, które mają atrybut Collection („Non-Parallel Collection”).
źródło
możesz użyć listy odtwarzania
kliknij prawym przyciskiem myszy metodę testową -> Dodaj do listy odtwarzania -> Nowa lista odtwarzania
wtedy możesz określić kolejność wykonywania, domyślnie jest tak, jak dodajesz je do listy odtwarzania, ale możesz zmienić plik listy odtwarzania, jak chcesz
źródło
Nie znam szczegółów, ale wygląda na to, że próbujesz przeprowadzić testy integracyjne, a nie jednostkowe . Gdybyś mógł wyodrębnić zależność od
ServiceHost
, prawdopodobnie ułatwiłoby to (i przyspieszy) testowanie. Na przykład możesz niezależnie przetestować następujące elementy:IServiceHostFactory
iIConfiguration
Narzędzia, które pomogłyby obejmować struktury izolacji (symulowanie) i (opcjonalnie) struktury kontenerów IoC. Widzieć:
źródło
Może możesz skorzystać z zaawansowanych testów jednostkowych . Pozwala zdefiniować kolejność, w jakiej przeprowadzasz test . Być może będziesz musiał utworzyć nowy plik cs do obsługi tych testów.
Oto, jak możesz nagiąć metody testowe, aby działały w żądanej kolejności.
[Test] [Sequence(16)] [Requires("POConstructor")] [Requires("WorkOrderConstructor")] public void ClosePO() { po.Close(); // one charge slip should be added to both work orders Assertion.Assert(wo1.ChargeSlipCount==1, "First work order: ChargeSlipCount not 1."); Assertion.Assert(wo2.ChargeSlipCount==1, "Second work order: ChargeSlipCount not 1."); ... }
Daj mi znać, czy to działa.
źródło
Dla mnie w aplikacji .Net Core Console, gdy chciałem uruchamiać metody testowe (nie klasy) synchronicznie, jedynym rozwiązaniem, które działało, było to opisane na tym blogu: xUnit: Control the Test Execution Order
źródło
Dodałem atrybut [Collection ("Sequential")] w klasie bazowej:
namespace IntegrationTests { [Collection("Sequential")] public class SequentialTest : IDisposable ... public class TestClass1 : SequentialTest { ... } public class TestClass2 : SequentialTest { ... } }
źródło
Żadna z dotychczas sugerowanych odpowiedzi nie zadziałała dla mnie. Mam aplikację dotnet core z XUnit 2.4.1. Osiągnąłem pożądane zachowanie, stosując obejście, umieszczając blokadę w każdym teście jednostkowym. W moim przypadku nie przejmowałem się kolejnością uruchamiania, tylko to, że testy były sekwencyjne.
public class TestClass { [Fact] void Test1() { lock (this) { //Test Code } } [Fact] void Test2() { lock (this) { //Test Code } } }
źródło