Class ComposedFixture
Implements an ITestFixture that is composed of other test fixtures.
Implements
Inherited Members
Namespace: Neon.Xunit
Assembly: Neon.Xunit.dll
Syntax
public class ComposedFixture : TestFixture, ITestFixture
Remarks
note
IMPORTANT: The base Neon TestFixture implementation DOES NOT
support parallel test execution. You need to explicitly disable parallel execution in
all test assemblies that rely on thesex test fixtures by adding a C# file called
AssemblyInfo.cs
with:
[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)]
and then define your test classes like:
public class MyTests : IClassFixture<ComposedFixture>, IDisposable
{
[Collection(TestCollection.NonParallel)]
[CollectionDefinition(TestCollection.NonParallel, DisableParallelization = true)]
[Fact]
public void Test()
{
}
}
Derived test fixtures that modify global machine or other environmental state
must implement a public static void EnsureReset()
method resets the state
to a reasonable default. These will be reflected and called when the first
TestFixture is created by the test runner for every test class.
INTEGRATION TESTING
One use case we've found valuable is to use ComposedFixture to enulate an entire cluster of services as a unit test or in a console application. The idea is to have the unit test or console app code reference all of your service assemblies and then add these services to a ComposedFixture as well as any database and/or workflow engines and then start the composed fixtures.
This can require a lot of memory and CPU, but it can be really nice to have an entire service running in Visual Studio where you can set breakpoints anywhere. We've emulated clusters with well over 75 services this way.
One of the problems we encountered is that it can take several minutes for the all of
the services and other subfixtures to start because they are started one at a time
by default. We've enhanced this class so that you can optionally start groups of
subfixtures in parallel via the optional group
parameter. By default,
this is passed as -1, indicating that subfixtures with group=-1
will
be started one at a time in the group they were added to the ComposedFixture
and these will be started before any other fixtures. This results in the same behavior
as older versions of the fixture.
Fixtures added with group
passed as zero or a positive number are started when
you call Start(Action). This starts the subfixtures in the same group in
parallel with any others in the group. Note that we'll start at the lowest group number
and wait for all fixtures to start before moving on to the next group.
CodeFixture can be used as a way to inject custom code what will be executed while ComposedFixture is starting subfixtures. The basic idea is to add things like database fixtures as group=0 and then add a CodeFixture with a custom action as group=1 followed by NeonServiceFixture<TService> and/or other fixtures as group=2+.
Then the ComposedFixture will start the database first, followed by the CodeFixture where the action has an opportunity to initialize the database before the remaining fixtures are started.
Constructors
ComposedFixture()
Constructor.
Declaration
public ComposedFixture()
Properties
Children
Returns the subfixtures.
Declaration
public IEnumerable<ITestFixture> Children { get; }
Property Value
Type | Description |
---|---|
IEnumerable<ITestFixture> |
Count
Returns the number of fixtures in the set.
Declaration
public int Count { get; }
Property Value
Type | Description |
---|---|
int |
this[int]
Returns the fixture at the specified index (based on the order the fixture was added).
Declaration
public ITestFixture this[int index] { get; }
Parameters
Type | Name | Description |
---|---|---|
int | index | specifies the index of the desired fixture. |
Property Value
Type | Description |
---|---|
ITestFixture | The test fixture. |
Exceptions
Type | Condition |
---|---|
IndexOutOfRangeException | Thrown if |
this[string]
Returns the named test fixture.
Declaration
public ITestFixture this[string name] { get; }
Parameters
Type | Name | Description |
---|---|---|
string | name | The fixture name (case insensitive). |
Property Value
Type | Description |
---|---|
ITestFixture | The test fixture. |
Exceptions
Type | Condition |
---|---|
KeyNotFoundException | Thrown if the named fixture does not exist. |
Methods
AddFixture<TFixture>(string, TFixture, Action<TFixture>, int)
Adds a named ITestFixture.
Declaration
public void AddFixture<TFixture>(string name, TFixture subFixture, Action<TFixture> action = null, int group = -1) where TFixture : class, ITestFixture
Parameters
Type | Name | Description |
---|---|---|
string | name | The fixture name (case insenstitive). |
TFixture | subFixture | The subfixture instance. |
Action<TFixture> | action | The optional Action to be called when the fixture is initialized. This can be used for things like waiting until the service is actually ready before returning. |
int | group | Optionally specifies the fixture group. Fixtures with |
Type Parameters
Name | Description |
---|---|
TFixture | The new fixture type. |
Remarks
note
This method doesn't work for NeonServiceFixture<TService> based fixtures. Use AddServiceFixture<TService>(string, NeonServiceFixture<TService>, Func<TService>, ServiceMap, TimeSpan, int) instead.
AddServiceFixture<TService>(string, NeonServiceFixture<TService>, Func<TService>, ServiceMap, TimeSpan, int)
Adds a named NeonServiceFixture<TService> fixture.
Declaration
public void AddServiceFixture<TService>(string name, NeonServiceFixture<TService> subFixture, Func<TService> serviceCreator, ServiceMap serviceMap = null, TimeSpan startTimeout = default, int group = -1) where TService : NeonService
Parameters
Type | Name | Description |
---|---|---|
string | name | The fixture name (case insenstitive). |
NeonServiceFixture<TService> | subFixture | The subfixture being added. |
Func<TService> | serviceCreator | Callback that creates and returns the new service instance. |
ServiceMap | serviceMap | Optionally specifies a ServiceMap. When a service map is passed and there's a ServiceDescription for the created service, then the fixture will configure the service with TestEnvironmentVariables, TestBinaryConfigFiles, and TestTextConfigFiles before starting the service. |
TimeSpan | startTimeout | Optionally specifies maximum time to wait for the service to transition to the running state. |
int | group | Optionally specifies the fixture group. Fixtures with |
Type Parameters
Name | Description |
---|---|
TService | The service type (derived from NeonService). |
Dispose(bool)
Disposes all fixtures in the set.
Declaration
protected override void Dispose(bool disposing)
Parameters
Type | Name | Description |
---|---|---|
bool | disposing | Pass |
Overrides
~ComposedFixture()
Finalizer.
Declaration
protected ~ComposedFixture()
GetEnumerator()
Enumerates the named test fixtures in the set.
Declaration
public IEnumerator<KeyValuePair<string, ITestFixture>> GetEnumerator()
Returns
Type | Description |
---|---|
IEnumerator<KeyValuePair<string, ITestFixture>> | The fixtures as |
Reset()
INTERNAL USE ONLY: Resets the fixture state.
Declaration
public override void Reset()
Overrides
Start(Action)
Starts the fixture if it hasn't already been started including invoking the optional Action when the first time Start(Action) is called for a fixture instance.
Declaration
public override TestFixtureStatus Start(Action action = null)
Parameters
Type | Name | Description |
---|---|---|
Action | action | The optional custom start action. noteThis is generally intended for use when developing custom test fixtures. |
Returns
Type | Description |
---|---|
TestFixtureStatus | Started if the fixture wasn't previously started and this method call started it or AlreadyRunning if the fixture was already running. |
Overrides
Exceptions
Type | Condition |
---|---|
InvalidOperationException | Thrown if this is called from within the Action. |