Я пытаюсь выполнить модульное тестирование написанного мной механизма управления хостом WCF. Механизм в основном создает экземпляры ServiceHost на лету на основе конфигурации. Это позволяет нам динамически перенастраивать, какие службы доступны, без необходимости отключать их все и перезапускать их всякий раз, когда добавляется новая служба или удаляется старая.
Однако я столкнулся с трудностями при модульном тестировании этого механизма управления хостом из-за того, как работает ServiceHost. Если ServiceHost уже был создан, открыт и еще не закрыт для конкретной конечной точки, другой ServiceHost для той же конечной точки не может быть создан, что приведет к исключению. Из-за того, что современные платформы модульного тестирования распараллеливают выполнение тестов, у меня нет эффективного способа модульного тестирования этого фрагмента кода.
Я использовал xUnit.NET, надеясь, что благодаря его расширяемости я смогу найти способ заставить его запускать тесты последовательно. Однако мне не повезло. Я надеюсь, что кто-то здесь, на SO, столкнулся с подобной проблемой и знает, как заставить модульные тесты запускаться последовательно.
ПРИМЕЧАНИЕ. ServiceHost - это класс WCF, написанный Microsoft. У меня нет возможности изменить его поведение. Размещение каждой конечной точки службы только один раз также является правильным поведением ... однако это не особенно способствует модульному тестированию.
источник
TestServer
в докере. Поэтому мне пришлось сериализовать интеграционные тесты.Ответы:
Каждый тестовый класс представляет собой уникальный набор тестов, и тесты в нем будут выполняться последовательно, поэтому, если вы поместите все свои тесты в одну и ту же коллекцию, он будет запускаться последовательно.
Для этого в xUnit можно внести следующие изменения:
Следующее будет выполняться параллельно:
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"); } } }
Чтобы сделать его последовательным, вам просто нужно поместить оба тестовых класса в одну коллекцию:
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"); } } }
Для получения дополнительной информации вы можете перейти по этой ссылке
источник
Важно: этот ответ относится к .NET Framework. Для ядра dotnet см. Ответ Дмитрия относительно
xunit.runner.json
.Все хорошие модульные тесты должны быть на 100% изолированы. Использование общего состояния (например, в зависимости от
static
свойства, изменяемого каждым тестом) считается плохой практикой.Сказав это, на ваш вопрос о последовательном запуске тестов xUnit есть ответ! Я столкнулся с точно такой же проблемой, потому что моя система использует статический локатор сервисов (что далеко не идеально).
По умолчанию xUnit 2.x запускает все тесты параллельно. Это можно изменить для каждой сборки, указав
CollectionBehavior
в файле AssemblyInfo.cs в тестовом проекте.Для разделения сборки используйте:
using Xunit; [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
или вообще без распараллеливания:
[assembly: CollectionBehavior(DisableTestParallelization = true)]
Последний, вероятно, тот, который вам нужен. Дополнительную информацию о распараллеливании и настройке можно найти в документации xUnit .
источник
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerClass, DisableTestParallelization = true)]
. Благодаря тебе, @Squiggle, я могу запустить все свои тесты и пойти выпить кофе! :)Для проектов .NET Core создайте
xunit.runner.json
с помощью:{ "parallelizeAssembly": false, "parallelizeTestCollections": false }
Кроме того, вы
csproj
должны содержать<ItemGroup> <None Update="xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>
Для старых проектов .Net Core ваш
project.json
должен содержать"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
источник
<ItemGroup><None Include="xunit.runner.json" CopyToOutputDirectory="Always" /></ItemGroup>
или похож?<ItemGroup> <None Update="xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>
dotnet test --no-build -c Release -- xunit.parallelizeTestCollections=false
но у меня не получилось.Для проектов .NET Core вы можете настроить xUnit с помощью
xunit.runner.json
файла, как описано в https://xunit.github.io/docs/configuring-with-json.html .Параметр, который необходимо изменить, чтобы остановить выполнение параллельного теста, имеет значение по
parallelizeTestCollections
умолчаниюtrue
:Так
xunit.runner.json
выглядит минимал для этой цели{ "parallelizeTestCollections": false }
Как указано в документации, не забудьте включить этот файл в свою сборку:
Добавление
<Content Include=".\xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content>
в ваш
.csproj
файл, илиДобавление
"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
в ваш
project.json
файлв зависимости от типа вашего проекта.
Наконец, в дополнение к вышесказанному, если вы используете Visual Studio, убедитесь, что вы случайно не нажали кнопку « Выполнить тесты в параллельном режиме» , что приведет к параллельному запуску тестов, даже если вы отключили параллелизацию в
xunit.runner.json
. Дизайнеры пользовательского интерфейса Microsoft хитро сделали эту кнопку без надписи, чтобы ее было трудно заметить и на расстоянии примерно сантиметра от кнопки «Выполнить все» в обозревателе тестов, просто чтобы максимизировать вероятность того, что вы нажмете ее по ошибке и не поймете, почему ваши тесты внезапно выходят из строя:источник
xunit.runner.json
файла? И какое отношение указаниеxunit.runner.json
имеет к последовательному запуску тестов?Это старый вопрос, но я хотел написать решение для людей, ищущих новых, как я :)
Примечание. Я использую этот метод в тестах интеграции Dot Net Core WebUI с xunit версии 2.4.1.
Создайте пустой класс с именем NonParallelCollectionDefinitionClass и затем присвойте этому классу атрибут CollectionDefinition, как показано ниже. (Важная часть - параметр DisableParallelization = true.)
using Xunit; namespace WebUI.IntegrationTests.Common { [CollectionDefinition("Non-Parallel Collection", DisableParallelization = true)] public class NonParallelCollectionDefinitionClass { } }
После этого добавьте атрибут Collection в класс, который вы не хотите, чтобы он запускался параллельно, как показано ниже. (Важная часть - это имя коллекции. Оно должно совпадать с именем, используемым в CollectionDefinition)
namespace WebUI.IntegrationTests.Controllers.Users { [Collection("Non-Parallel Collection")] public class ChangePassword : IClassFixture<CustomWebApplicationFactory<Startup>> ...
Когда мы это делаем, сначала запускаются другие параллельные тесты. После этого запускаются другие тесты с атрибутом Коллекция («Непараллельная коллекция»).
источник
вы можете использовать плейлист
щелкните правой кнопкой мыши метод тестирования -> Добавить в список воспроизведения -> Новый список воспроизведения
затем вы можете указать порядок выполнения, по умолчанию, когда вы добавляете их в список воспроизведения, но вы можете изменить файл списка воспроизведения по своему усмотрению
источник
Я не знаю подробностей, но похоже, что вы пытаетесь провести интеграционное тестирование, а не модульное тестирование . Если бы вы могли изолировать зависимость от
ServiceHost
, это, вероятно, упростило бы (и ускорило) ваше тестирование. Так (например) вы можете самостоятельно протестировать следующее:IServiceHostFactory
иIConfiguration
Инструменты, которые помогут включить изоляционные (имитирующие) фреймворки и (необязательно) фреймворки контейнеров IoC. Увидеть:
источник
Возможно, вы сможете использовать Advanced Unit Testing . Это позволяет вам определить последовательность, в которой вы запускаете тест . Поэтому вам, возможно, придется создать новый файл cs для размещения этих тестов.
Вот как можно изменить методы тестирования, чтобы они работали в нужной вам последовательности.
[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."); ... }
Дайте мне знать, работает ли это.
источник
Для меня в приложении .Net Core Console, когда я хотел запускать тестовые методы (не классы) синхронно, единственное решение, которое сработало, было описано в этом блоге: xUnit: Control the Test Execution Order
источник
Я добавил атрибут [Collection ("Sequential")] в базовый класс:
namespace IntegrationTests { [Collection("Sequential")] public class SequentialTest : IDisposable ... public class TestClass1 : SequentialTest { ... } public class TestClass2 : SequentialTest { ... } }
источник
Ни один из предложенных ответов пока не помог мне. У меня есть приложение ядра dotnet с XUnit 2.4.1. Я добился желаемого поведения с помощью обходного пути, установив вместо этого блокировку в каждом модульном тесте. В моем случае меня не волновал порядок выполнения, просто тесты были последовательными.
public class TestClass { [Fact] void Test1() { lock (this) { //Test Code } } [Fact] void Test2() { lock (this) { //Test Code } } }
источник