diff --git a/examples/Elastic.Ephemeral.Example/Elastic.Ephemeral.Example.csproj b/examples/Elastic.Ephemeral.Example/Elastic.Ephemeral.Example.csproj
index bc13e1f..e612ad6 100644
--- a/examples/Elastic.Ephemeral.Example/Elastic.Ephemeral.Example.csproj
+++ b/examples/Elastic.Ephemeral.Example/Elastic.Ephemeral.Example.csproj
@@ -13,7 +13,7 @@
   
 
   
-    
+    
   
 
 
diff --git a/examples/Elastic.Ephemeral.Example/Program.cs b/examples/Elastic.Ephemeral.Example/Program.cs
index efd2487..ffe89e1 100644
--- a/examples/Elastic.Ephemeral.Example/Program.cs
+++ b/examples/Elastic.Ephemeral.Example/Program.cs
@@ -29,7 +29,7 @@
 if (cluster.DetectedProxy != DetectedProxySoftware.None)
 	transportConfig = transportConfig.Proxy(new Uri("http://localhost:8080/"), null!, null!);
 
-var transport = new DefaultHttpTransport(transportConfig);
+var transport = new DistributedTransport(transportConfig);
 
 var response = await transport.RequestAsync(HttpMethod.GET, "/");
 Console.WriteLine(response);
diff --git a/examples/Elastic.Xunit.ExampleComplex/Setup.cs b/examples/Elastic.Xunit.ExampleComplex/Setup.cs
index 31266be..905289a 100644
--- a/examples/Elastic.Xunit.ExampleComplex/Setup.cs
+++ b/examples/Elastic.Xunit.ExampleComplex/Setup.cs
@@ -19,13 +19,12 @@ public class MyRunOptions : ElasticXunitRunOptions
 	{
 		public MyRunOptions()
 		{
-			ClusterFilter = "";
-			RunUnitTests = false;
+			RunUnitTests = true;
 			RunIntegrationTests = true;
 			IntegrationTestsMayUseAlreadyRunningNode = true;
 			Version = TestVersion;
 		}
 
-		public static ElasticVersion TestVersion { get; } = "8.0.0-SNAPSHOT";
+		public static ElasticVersion TestVersion { get; } = "latest-8";
 	}
 }
diff --git a/examples/Elastic.Xunit.ExampleComplex/TestWithoutClusterFixture.cs b/examples/Elastic.Xunit.ExampleComplex/TestWithoutClusterFixture.cs
index 9594304..3fab22a 100644
--- a/examples/Elastic.Xunit.ExampleComplex/TestWithoutClusterFixture.cs
+++ b/examples/Elastic.Xunit.ExampleComplex/TestWithoutClusterFixture.cs
@@ -8,7 +8,6 @@
 
 namespace Elastic.Xunit.ExampleComplex
 {
-	[IntegrationTestCluster(typeof(TestCluster))]
 	[SkipVersion("<6.3.0", "")]
 	public class TestWithoutClusterFixture
 	{
diff --git a/examples/Elastic.Xunit.ExampleComplex/Tests.cs b/examples/Elastic.Xunit.ExampleComplex/Tests.cs
index 48a565e..8a97d8d 100644
--- a/examples/Elastic.Xunit.ExampleComplex/Tests.cs
+++ b/examples/Elastic.Xunit.ExampleComplex/Tests.cs
@@ -2,17 +2,17 @@
 // Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
 // See the LICENSE file in the project root for more information
 
+using Elastic.Elasticsearch.Managed;
 using Elastic.Elasticsearch.Xunit.XunitPlumbing;
 using Elasticsearch.Net;
 using FluentAssertions;
+using Xunit;
 
 namespace Elastic.Xunit.ExampleComplex
 {
 	public class MyTestClass : ClusterTestClassBase
 	{
-		public MyTestClass(TestCluster cluster) : base(cluster)
-		{
-		}
+		public MyTestClass(TestCluster cluster) : base(cluster) { }
 
 		[I]
 		public void SomeTest()
@@ -22,34 +22,70 @@ public void SomeTest()
 			info.IsValid.Should().BeTrue();
 
 			Client.CreateIndex("INASda");
+			Client.LowLevel.Search(PostData.Serializable(new {query = new {query_string = 1}}));
+		}
+	}
 
+	public class Tests1 : ClusterTestClassBase
+	{
+		public Tests1(TestCluster cluster) : base(cluster) { }
 
-			Client.LowLevel.Search(PostData.Serializable(new {query = new {query_string = 1}}));
+		[U] public void Unit1Test() => (1 + 1).Should().Be(2);
+		[U] public void Unit1Test1() => (1 + 1).Should().Be(2);
+		[U] public void Unit1Test2() => (1 + 1).Should().Be(2);
+		[U] public void Unit1Test3() => (1 + 1).Should().Be(2);
+		[U] public void Unit1Test4() => (1 + 1).Should().Be(2);
+		[U] public void Unit1Test5() => (1 + 1).Should().Be(2);
+		[U] public void Unit1Test6() => (1 + 1).Should().Be(2);
+	}
+
+	public class Tests3
+	{
+		[U] public void Unit3Test() => (1 + 1).Should().Be(2);
+		[U] public void Unit3Test1() => (1 + 1).Should().Be(2);
+		[U] public void Unit3Test2() => (1 + 1).Should().Be(2);
+		[U] public void Unit3Test3() => (1 + 1).Should().Be(2);
+		[U] public void Unit3Test4() => (1 + 1).Should().Be(2);
+		[U] public void Unit3Test5() => (1 + 1).Should().Be(2);
+		[U] public void Unit3Test6() => (1 + 1).Should().Be(2);
+	}
+
+	public class Tests2 : ClusterTestClassBase
+	{
+		public Tests2(TestCluster cluster) : base(cluster) { }
+
+		[U] public void Unit2Test() => (1 + 1).Should().Be(2);
+		[U] public void Unit2Test1() => (1 + 1).Should().Be(2);
+		[U] public void Unit2Test2() => (1 + 1).Should().Be(2);
+		[U] public void Unit2Test3() => (1 + 1).Should().Be(2);
+		[U] public void Unit2Test4() => (1 + 1).Should().Be(2);
+		[U] public void Unit2Test5() => (1 + 1).Should().Be(2);
+		[U] public void Unit2Test6() => (1 + 1).Should().Be(2);
+	}
+
+	public class MyGenericTestClass : ClusterTestClassBase
+	{
+		public MyGenericTestClass(TestGenericCluster cluster) : base(cluster) { }
+
+		[I] public void SomeTest()
+		{
+			var info = Client.RootNodeInfo();
+
+			info.IsValid.Should().BeTrue();
 		}
+		[U] public void MyGenericUnitTest() => (1 + 1).Should().Be(2);
+		[U] public void MyGenericUnitTest1() => (1 + 1).Should().Be(2);
+		[U] public void MyGenericUnitTest2() => (1 + 1).Should().Be(2);
+		[U] public void MyGenericUnitTest3() => (1 + 1).Should().Be(2);
+		[U] public void MyGenericUnitTest4() => (1 + 1).Should().Be(2);
+		[U] public void MyGenericUnitTest5() => (1 + 1).Should().Be(2);
+		[U] public void MyGenericUnitTest6() => (1 + 1).Should().Be(2);
 	}
-//
-//	public class MyGenericTestClass : ClusterTestClassBase
-//	{
-//		public MyGenericTestClass(TestGenericCluster cluster) : base(cluster) { }
-//
-//		[I] public void SomeTest()
-//		{
-//			var info = this.Client.RootNodeInfo();
-//
-//			info.IsValid.Should().BeTrue();
-//		}
-//		[U] public void UnitTest()
-//		{
-//			(1 + 1).Should().Be(2);
-//		}
-//	}
 
 	[SkipVersion("<6.2.0", "")]
 	public class SkipTestClass : ClusterTestClassBase
 	{
-		public SkipTestClass(TestGenericCluster cluster) : base(cluster)
-		{
-		}
+		public SkipTestClass(TestGenericCluster cluster) : base(cluster) { }
 
 		[I]
 		public void SomeTest()
@@ -62,4 +98,12 @@ public void SomeTest()
 		[U]
 		public void UnitTest() => (1 + 1).Should().Be(2);
 	}
+
+	public class DirectInterfaceTests : IClusterFixture
+	{
+		public DirectInterfaceTests(TestGenericCluster cluster) { }
+
+		[U]
+		public void DirectUnitTest() => (1 + 1).Should().Be(2);
+	}
 }
diff --git a/examples/Elastic.Xunit.ExampleMinimal/ExampleTest.cs b/examples/Elastic.Xunit.ExampleMinimal/ExampleTest.cs
index 0b44131..493522c 100644
--- a/examples/Elastic.Xunit.ExampleMinimal/ExampleTest.cs
+++ b/examples/Elastic.Xunit.ExampleMinimal/ExampleTest.cs
@@ -21,7 +21,7 @@ public class MyTestCluster : XunitClusterBase
 		///     We pass our configuration instance to the base class.
 		///     We only configure it to run version 6.2.3 here but lots of additional options are available.
 		/// 
-		public MyTestCluster() : base(new XunitClusterConfiguration("8.0.0-SNAPSHOT") { })
+		public MyTestCluster() : base(new XunitClusterConfiguration("latest-8") { })
 		{
 		}
 	}
diff --git a/examples/ScratchPad/Program.cs b/examples/ScratchPad/Program.cs
index 5ff29df..dabd8eb 100644
--- a/examples/ScratchPad/Program.cs
+++ b/examples/ScratchPad/Program.cs
@@ -24,8 +24,8 @@ public static class Program
 
 		public static int Main()
 		{
-			//ResolveVersions();
-			ManualConfigRun();
+			ResolveVersions();
+			//ManualConfigRun();
 			//ValidateCombinations.Run();
 			return 0;
 		}
@@ -87,8 +87,8 @@ private static void ResolveVersions()
 		{
 			var versions = new[]
 			{
-				"8.0.0-SNAPSHOT", "7.0.0-beta1", "6.6.1", "latest-7", "latest", "7.0.0", "7.4.0-SNAPSHOT",
-				"957e3089:7.2.0", "latest-6"
+				"latest-8", "7.0.0-beta1", "6.6.1", "latest-7", "latest", "7.0.0", "7.4.0-SNAPSHOT",
+				"957e3089:7.2.0"
 			};
 			//versions = new[] {"latest-7"};
 			var products = new Product[]
diff --git a/src/Elastic.Elasticsearch.Xunit/Elastic.Elasticsearch.Xunit.csproj b/src/Elastic.Elasticsearch.Xunit/Elastic.Elasticsearch.Xunit.csproj
index 9877920..6015f45 100644
--- a/src/Elastic.Elasticsearch.Xunit/Elastic.Elasticsearch.Xunit.csproj
+++ b/src/Elastic.Elasticsearch.Xunit/Elastic.Elasticsearch.Xunit.csproj
@@ -2,10 +2,12 @@
   
     netstandard2.0;netstandard2.1;net462
     True
+    False
     Provides an Xunit test framework allowing you to run integration tests against local ephemeral Elasticsearch clusters
     elastic,elasticsearch,xunit,cluster,integration,test,ephemeral
   
   
+    
     
   
   
diff --git a/src/Elastic.Elasticsearch.Xunit/ElasticXunitConfigurationAttribute.cs b/src/Elastic.Elasticsearch.Xunit/ElasticXunitConfigurationAttribute.cs
index 328cee6..f7f280e 100644
--- a/src/Elastic.Elasticsearch.Xunit/ElasticXunitConfigurationAttribute.cs
+++ b/src/Elastic.Elasticsearch.Xunit/ElasticXunitConfigurationAttribute.cs
@@ -3,31 +3,20 @@
 // See the LICENSE file in the project root for more information
 
 using System;
+using Nullean.Xunit.Partitions;
 
-namespace Elastic.Elasticsearch.Xunit
-{
-	/// 
-	///     An assembly attribute that specifies the 
-	///     for Xunit tests within the assembly.
-	/// 
-	[AttributeUsage(AttributeTargets.Assembly)]
-	public class ElasticXunitConfigurationAttribute : Attribute
-	{
-		/// 
-		///     Creates a new instance of 
-		/// 
-		/// 
-		///     A type deriving from  that specifies the run options
-		/// 
-		public ElasticXunitConfigurationAttribute(Type type)
-		{
-			var options = Activator.CreateInstance(type) as ElasticXunitRunOptions;
-			Options = options ?? new ElasticXunitRunOptions();
-		}
+namespace Elastic.Elasticsearch.Xunit;
 
-		/// 
-		///     The run options
-		/// 
-		public ElasticXunitRunOptions Options { get; }
-	}
+/// 
+///     An assembly attribute that specifies the 
+///     for Xunit tests within the assembly.
+/// 
+[AttributeUsage(AttributeTargets.Assembly)]
+public class ElasticXunitConfigurationAttribute : PartitionOptionsAttribute
+{
+	/// Creates a new instance of .
+	/// 
+	/// A type deriving from  that specifies the run options
+	/// 
+	public ElasticXunitConfigurationAttribute(Type type) : base(type) { }
 }
diff --git a/src/Elastic.Elasticsearch.Xunit/ElasticXunitRunOptions.cs b/src/Elastic.Elasticsearch.Xunit/ElasticXunitRunOptions.cs
index 26fb4db..5215d3b 100644
--- a/src/Elastic.Elasticsearch.Xunit/ElasticXunitRunOptions.cs
+++ b/src/Elastic.Elasticsearch.Xunit/ElasticXunitRunOptions.cs
@@ -3,18 +3,20 @@
 // See the LICENSE file in the project root for more information
 
 using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
+using System.Linq;
+using System.Runtime.Serialization;
 using Elastic.Elasticsearch.Xunit.XunitPlumbing;
 using Elastic.Stack.ArtifactsApi;
+using Nullean.Xunit.Partitions;
+using Xunit.Abstractions;
+using static System.StringSplitOptions;
 
 namespace Elastic.Elasticsearch.Xunit
 {
 	/// 
 	///     The Xunit test runner options
 	/// 
-	public class ElasticXunitRunOptions
+	public class ElasticXunitRunOptions : PartitionOptions
 	{
 		/// 
 		///     Informs the runner whether we expect to run integration tests. Defaults to true
@@ -35,16 +37,46 @@ public class ElasticXunitRunOptions
 		public bool RunUnitTests { get; set; }
 
 		/// 
-		///     A global test filter that can be used to only run certain tests.
+		///     A global cluster filter that can be used to only run certain cluster's tests.
 		///     Accepts a comma separated list of filters
 		/// 
-		public string TestFilter { get; set; }
+		[Obsolete("Use PartitionFilterRegex instead", false)]
+		[IgnoreDataMember]
+		public string ClusterFilter
+		{
+			get => PartitionFilterRegex;
+			set
+			{
+				if (string.IsNullOrWhiteSpace(value)) PartitionFilterRegex = value;
+				else
+				{
+					//attempt at being backwards compatible with old way of filtering
+					var re = string.Join("|", value.Split(new[] { ','}, RemoveEmptyEntries).Select(s => s.Trim()));
+					PartitionFilterRegex = re;
+				}
+			}
+		}
 
 		/// 
-		///     A global cluster filter that can be used to only run certain cluster's tests.
+		///     A global test filter that can be used to only run certain cluster's tests.
 		///     Accepts a comma separated list of filters
 		/// 
-		public string ClusterFilter { get; set; }
+		[Obsolete("Use ParitionFilterRegex instead", false)]
+		[IgnoreDataMember]
+		public string TestFilter
+		{
+			get => TestFilterRegex;
+			set
+			{
+				if (string.IsNullOrWhiteSpace(value)) TestFilterRegex = value;
+				else
+				{
+					//attempt at being backwards compatible with old way of filtering
+					var re = string.Join("|", value.Split(new[] { ','}, RemoveEmptyEntries).Select(s => s.Trim()));
+					TestFilterRegex = re;
+				}
+			}
+		}
 
 		/// 
 		///     Informs the runner what version of Elasticsearch is under test. Required for
@@ -52,22 +84,38 @@ public class ElasticXunitRunOptions
 		/// 
 		public ElasticVersion Version { get; set; }
 
-		/// 
-		///     Called when the tests have finished running successfully
-		/// 
-		/// Per cluster timings of the total test time, including starting Elasticsearch
-		/// All collection of failed cluster, failed tests tuples
-		public virtual void OnTestsFinished(Dictionary runnerClusterTotals,
-			ConcurrentBag> runnerFailedCollections)
+		public override void SetOptions(ITestFrameworkDiscoveryOptions discoveryOptions)
 		{
+			base.SetOptions(discoveryOptions);
+			discoveryOptions.SetValue(nameof(Version), Version);
+			discoveryOptions.SetValue(nameof(RunIntegrationTests), RunIntegrationTests);
+			discoveryOptions.SetValue(
+				nameof(IntegrationTestsMayUseAlreadyRunningNode),
+				IntegrationTestsMayUseAlreadyRunningNode
+			);
+			discoveryOptions.SetValue(nameof(RunUnitTests), RunUnitTests);
+#pragma warning disable CS0618 // Type or member is obsolete
+			discoveryOptions.SetValue(nameof(TestFilter), TestFilter);
+			discoveryOptions.SetValue(nameof(ClusterFilter), ClusterFilter);
+#pragma warning restore CS0618 // Type or member is obsolete
 		}
 
-		/// 
-		///     Called before tests run. An ideal place to perform actions such as writing information to
-		///     .
-		/// 
-		public virtual void OnBeforeTestsRun()
+		public override void SetOptions(ITestFrameworkExecutionOptions executionOptions)
 		{
+
+			base.SetOptions(executionOptions);
+			executionOptions.SetValue(nameof(Version), Version);
+			executionOptions.SetValue(nameof(RunIntegrationTests), RunIntegrationTests);
+			executionOptions.SetValue(
+				nameof(IntegrationTestsMayUseAlreadyRunningNode),
+				IntegrationTestsMayUseAlreadyRunningNode
+			);
+			executionOptions.SetValue(nameof(RunUnitTests), RunUnitTests);
+#pragma warning disable CS0618 // Type or member is obsolete
+			executionOptions.SetValue(nameof(TestFilter), TestFilter);
+			executionOptions.SetValue(nameof(ClusterFilter), ClusterFilter);
+#pragma warning restore CS0618 // Type or member is obsolete
+
 		}
 	}
 }
diff --git a/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFramework.cs b/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFramework.cs
index c329c03..baf0588 100644
--- a/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFramework.cs
+++ b/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFramework.cs
@@ -3,30 +3,25 @@
 // See the LICENSE file in the project root for more information
 
 using System.Reflection;
+using Elastic.Elasticsearch.Xunit.XunitPlumbing;
 using Xunit.Abstractions;
 using Xunit.Sdk;
+using Nullean.Xunit.Partitions;
+using Nullean.Xunit.Partitions.Sdk;
 
-namespace Elastic.Elasticsearch.Xunit.Sdk
-{
-	public class ElasticTestFramework : XunitTestFramework
-	{
-		public ElasticTestFramework(IMessageSink messageSink) : base(messageSink)
-		{
-		}
-
-		protected override ITestFrameworkDiscoverer CreateDiscoverer(IAssemblyInfo assemblyInfo) =>
-			new ElasticTestFrameworkDiscoverer(assemblyInfo, SourceInformationProvider, DiagnosticMessageSink);
+namespace Elastic.Elasticsearch.Xunit.Sdk;
 
-		protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
-		{
-			var assembly = Assembly.Load(assemblyName);
-			var options = assembly.GetCustomAttribute()?.Options ??
-			              new ElasticXunitRunOptions();
+// ReSharper disable once UnusedType.Global
+public class ElasticTestFramework : PartitionTestFramework
+{
+	public ElasticTestFramework(IMessageSink messageSink) : base(messageSink) { }
+}
 
-			return new TestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink)
-			{
-				Options = options
-			};
-		}
-	}
+public class ElasticTestFrameworkDiscovererFactory : ITestFrameworkDiscovererFactory
+{
+	public XunitTestFrameworkDiscoverer Create(
+		IAssemblyInfo assemblyInfo, ISourceInformationProvider sourceProvider, IMessageSink diagnosticMessageSink
+	)
+		where TOptions : PartitionOptions, new() =>
+		new PartitionTestFrameworkDiscoverer(assemblyInfo, sourceProvider, diagnosticMessageSink, typeof(IClusterFixture<>));
 }
diff --git a/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFrameworkDiscoverer.cs b/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFrameworkDiscoverer.cs
deleted file mode 100644
index 9edc1e9..0000000
--- a/src/Elastic.Elasticsearch.Xunit/Sdk/ElasticTestFrameworkDiscoverer.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using System.Reflection;
-using Xunit.Abstractions;
-using Xunit.Sdk;
-
-namespace Elastic.Elasticsearch.Xunit.Sdk
-{
-	public class ElasticTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer
-	{
-		public ElasticTestFrameworkDiscoverer(IAssemblyInfo assemblyInfo, ISourceInformationProvider sourceProvider,
-			IMessageSink diagnosticMessageSink, IXunitTestCollectionFactory collectionFactory = null) : base(
-			assemblyInfo, sourceProvider, diagnosticMessageSink, collectionFactory)
-		{
-			var a = Assembly.Load(new AssemblyName(assemblyInfo.Name));
-			var options = a.GetCustomAttribute()?.Options ??
-			              new ElasticXunitRunOptions();
-			Options = options;
-		}
-
-		/// 
-		///     The options for
-		/// 
-		public ElasticXunitRunOptions Options { get; }
-
-		protected override bool FindTestsForType(ITestClass testClass, bool includeSourceInformation,
-			IMessageBus messageBus, ITestFrameworkDiscoveryOptions discoveryOptions)
-		{
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.Version), Options.Version);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests), Options.RunIntegrationTests);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.IntegrationTestsMayUseAlreadyRunningNode),
-				Options.IntegrationTestsMayUseAlreadyRunningNode);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.RunUnitTests), Options.RunUnitTests);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.TestFilter), Options.TestFilter);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.ClusterFilter), Options.ClusterFilter);
-			return base.FindTestsForType(testClass, includeSourceInformation, messageBus, discoveryOptions);
-		}
-	}
-}
diff --git a/src/Elastic.Elasticsearch.Xunit/Sdk/ForEachAsyncExtensions.cs b/src/Elastic.Elasticsearch.Xunit/Sdk/ForEachAsyncExtensions.cs
deleted file mode 100644
index 87bf715..0000000
--- a/src/Elastic.Elasticsearch.Xunit/Sdk/ForEachAsyncExtensions.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace Elastic.Elasticsearch.Xunit.Sdk
-{
-	internal static class ForEachAsyncExtensions
-	{
-		internal static Task ForEachAsync(this IEnumerable source, int dop, Func body) =>
-			Task.WhenAll(
-				from partition in Partitioner.Create(source).GetPartitions(dop)
-				select Task.Run(async delegate
-				{
-					using (partition)
-						while (partition.MoveNext())
-							await body(partition.Current).ConfigureAwait(false);
-				}));
-	}
-}
diff --git a/src/Elastic.Elasticsearch.Xunit/Sdk/TestAssemblyRunner.cs b/src/Elastic.Elasticsearch.Xunit/Sdk/TestAssemblyRunner.cs
index 8bd70da..798fe16 100644
--- a/src/Elastic.Elasticsearch.Xunit/Sdk/TestAssemblyRunner.cs
+++ b/src/Elastic.Elasticsearch.Xunit/Sdk/TestAssemblyRunner.cs
@@ -13,271 +13,99 @@
 using Elastic.Elasticsearch.Ephemeral;
 using Elastic.Elasticsearch.Ephemeral.Tasks.ValidationTasks;
 using Elastic.Elasticsearch.Xunit.XunitPlumbing;
+using Nullean.Xunit.Partitions.Sdk;
 using Xunit.Abstractions;
 using Xunit.Sdk;
 
 namespace Elastic.Elasticsearch.Xunit.Sdk
 {
-	internal class TestAssemblyRunner : XunitTestAssemblyRunner
-	{
-		private readonly Dictionary> _assemblyFixtureMappings =
-			new Dictionary>();
-
-		private readonly List, GroupedByCluster>> _grouped;
 
+	public class TestAssemblyRunnerFactory : ITestAssemblyRunnerFactory
+	{
+		public XunitTestAssemblyRunner Create(ITestAssembly testAssembly, IEnumerable testCases,
+			IMessageSink diagnosticMessageSink,
+			IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) =>
+			new TestAssemblyRunner(testAssembly, testCases, diagnosticMessageSink, executionMessageSink,
+				executionOptions);
+	}
+	internal class TestAssemblyRunner : PartitionTestAssemblyRunner>
+	{
 		public TestAssemblyRunner(ITestAssembly testAssembly,
 			IEnumerable testCases,
 			IMessageSink diagnosticMessageSink,
 			IMessageSink executionMessageSink,
 			ITestFrameworkExecutionOptions executionOptions)
-			: base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions)
+			: base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions, typeof(IClusterFixture<>))
 		{
-			var tests = OrderTestCollections();
 			RunIntegrationTests = executionOptions.GetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests));
+			RunUnitTests = executionOptions.GetValue(nameof(ElasticXunitRunOptions.RunUnitTests));
 			IntegrationTestsMayUseAlreadyRunningNode =
 				executionOptions.GetValue(nameof(ElasticXunitRunOptions
 					.IntegrationTestsMayUseAlreadyRunningNode));
-			RunUnitTests = executionOptions.GetValue(nameof(ElasticXunitRunOptions.RunUnitTests));
-			TestFilter = executionOptions.GetValue(nameof(ElasticXunitRunOptions.TestFilter));
-			ClusterFilter = executionOptions.GetValue(nameof(ElasticXunitRunOptions.ClusterFilter));
-
-			//bit side effecty, sets up _assemblyFixtureMappings before possibly letting xunit do its regular concurrency thing
-			_grouped = (from c in tests
-				let cluster = ClusterFixture(c.Item2.First().TestMethod.TestClass)
-				let testcase = new GroupedByCluster {Collection = c.Item1, TestCases = c.Item2, Cluster = cluster}
-				group testcase by testcase.Cluster
-				into g
-				orderby g.Count() descending
-				select g).ToList();
 		}
 
-		public ConcurrentBag Summaries { get; } = new ConcurrentBag();
-
-		public ConcurrentBag> FailedCollections { get; } =
-			new ConcurrentBag>();
-
-		public Dictionary ClusterTotals { get; } = new Dictionary();
-
 		private bool RunIntegrationTests { get; }
 		private bool IntegrationTestsMayUseAlreadyRunningNode { get; }
 		private bool RunUnitTests { get; }
-		private string TestFilter { get; }
-		private string ClusterFilter { get; }
 
-		protected override Task RunTestCollectionAsync(IMessageBus b, ITestCollection c,
-			IEnumerable t, CancellationTokenSource s)
-		{
-			var aggregator = new ExceptionAggregator(Aggregator);
-			var fixtureObjects = new Dictionary();
-			foreach (var kv in _assemblyFixtureMappings) fixtureObjects.Add(kv.Key, kv.Value);
-			return new TestCollectionRunner(fixtureObjects, c, t, DiagnosticMessageSink, b, TestCaseOrderer, aggregator,
-					s)
-				.RunAsync();
-		}
-
-		protected override async Task RunTestCollectionsAsync(IMessageBus messageBus,
+		protected override async Task RunTestCollectionsAsync(IMessageBus bus,
 			CancellationTokenSource cancellationTokenSource)
 		{
-			//threading guess
-			var defaultMaxConcurrency = Environment.ProcessorCount * 4;
-
 			if (RunUnitTests && !RunIntegrationTests)
-				return await UnitTestPipeline(defaultMaxConcurrency, messageBus, cancellationTokenSource)
+				return await RunAllWithoutPartitionFixture(bus, cancellationTokenSource)
 					.ConfigureAwait(false);
 
-			return await IntegrationPipeline(defaultMaxConcurrency, messageBus, cancellationTokenSource)
+			return await RunAllTests(bus, cancellationTokenSource)
 				.ConfigureAwait(false);
 		}
 
-
-		private async Task UnitTestPipeline(int defaultMaxConcurrency, IMessageBus messageBus,
-			CancellationTokenSource ctx)
+		protected override async Task UseStateAndRun(
+			IEphemeralCluster cluster,
+			Func runGroup,
+			Func failAll
+		)
 		{
-			//make sure all clusters go in started state (won't actually start clusters in unit test mode)
-			//foreach (var g in this._grouped) g.Key?.Start();
-
-			var testFilters = CreateTestFilters(TestFilter);
-			await _grouped.SelectMany(g => g)
-				.ForEachAsync(defaultMaxConcurrency,
-					async g => { await RunTestCollections(messageBus, ctx, g, testFilters).ConfigureAwait(false); })
-				.ConfigureAwait(false);
-			//foreach (var g in this._grouped) g.Key?.Dispose();
-
-			return new RunSummary
+			using (cluster)
 			{
-				Total = Summaries.Sum(s => s.Total),
-				Failed = Summaries.Sum(s => s.Failed),
-				Skipped = Summaries.Sum(s => s.Skipped)
-			};
-		}
+				ElasticXunitRunner.CurrentCluster = cluster;
+				var clusterConfiguration = cluster.ClusterConfiguration;
+				var timeout = clusterConfiguration?.Timeout ?? TimeSpan.FromMinutes(2);
 
-		private async Task IntegrationPipeline(int defaultMaxConcurrency, IMessageBus messageBus,
-			CancellationTokenSource ctx)
-		{
-			var testFilters = CreateTestFilters(TestFilter);
-			foreach (var group in _grouped)
-			{
-				ElasticXunitRunner.CurrentCluster = @group.Key;
-				if (@group.Key == null)
+				var started = false;
+				try
 				{
-					var testCount = @group.SelectMany(q => q.TestCases).Count();
-					Console.WriteLine($" -> Several tests skipped because they have no cluster associated");
-					Summaries.Add(new RunSummary {Total = testCount, Skipped = testCount});
-					continue;
-				}
-
-				var type = @group.Key.GetType();
-				var clusterName = type.Name.Replace("Cluster", string.Empty) ?? "UNKNOWN";
-				if (!MatchesClusterFilter(clusterName)) continue;
-
-				var dop = @group.Key.ClusterConfiguration?.MaxConcurrency ?? defaultMaxConcurrency;
-				dop = dop <= 0 ? defaultMaxConcurrency : dop;
-
-				var timeout = @group.Key.ClusterConfiguration?.Timeout ?? TimeSpan.FromMinutes(2);
-
-				var skipReasons = @group.SelectMany(g => g.TestCases.Select(t => t.SkipReason)).ToList();
-				var allSkipped = skipReasons.All(r => !string.IsNullOrWhiteSpace(r));
-				if (allSkipped)
-				{
-					Console.WriteLine($" -> All tests from {clusterName} are skipped under the current configuration");
-					Summaries.Add(new RunSummary {Total = skipReasons.Count, Skipped = skipReasons.Count});
-					continue;
-				}
-
-				ClusterTotals.Add(clusterName, Stopwatch.StartNew());
+					if (!IntegrationTestsMayUseAlreadyRunningNode || !ValidateRunningVersion(cluster))
+						 cluster.Start(timeout);
 
-				bool ValidateRunningVersion()
-				{
-					try
-					{
-						var t = new ValidateRunningVersion();
-						t.Run(@group.Key);
-						return true;
-					}
-					catch (Exception)
-					{
-						return false;
-					}
+					started = true;
 				}
-
-				using (@group.Key)
+				catch (Exception e)
 				{
-					if (!IntegrationTestsMayUseAlreadyRunningNode || !ValidateRunningVersion())
-						@group.Key?.Start(timeout);
-
-					await @group.ForEachAsync(dop,
-							async g =>
-							{
-								await RunTestCollections(messageBus, ctx, g, testFilters).ConfigureAwait(false);
-							})
+					await failAll(e, $"Further logs might be available at: {cluster.ClusterConfiguration?.FileSystem?.LogsPath}")
 						.ConfigureAwait(false);
 				}
-
-				ClusterTotals[clusterName].Stop();
+				if (started)
+					await runGroup(clusterConfiguration?.MaxConcurrency).ConfigureAwait(false);
 			}
-
-			return new RunSummary
-			{
-				Total = Summaries.Sum(s => s.Total),
-				Failed = Summaries.Sum(s => s.Failed),
-				Skipped = Summaries.Sum(s => s.Skipped)
-			};
 		}
 
-		private async Task RunTestCollections(IMessageBus messageBus, CancellationTokenSource ctx, GroupedByCluster g,
-			string[] testFilters)
+		private static bool ValidateRunningVersion(IEphemeralCluster cluster)
 		{
-			var test = g.Collection.DisplayName.Replace("Test collection for", string.Empty).Trim();
-			if (!MatchesATestFilter(test, testFilters)) return;
-			if (testFilters.Length > 0) Console.WriteLine(" -> " + test);
-
 			try
 			{
-				var summary = await RunTestCollectionAsync(messageBus, g.Collection, g.TestCases, ctx)
-					.ConfigureAwait(false);
-				var type = g.Cluster?.GetType();
-				var clusterName = type?.Name.Replace("Cluster", "") ?? "UNKNOWN";
-				if (summary.Failed > 0)
-					FailedCollections.Add(Tuple.Create(clusterName, test));
-				Summaries.Add(summary);
+				var t = new ValidateRunningVersion();
+				t.Run(cluster);
+				return true;
 			}
-			catch (TaskCanceledException)
+			catch (Exception)
 			{
-				// TODO: What should happen here?
+				return false;
 			}
 		}
 
-		private static string[] CreateTestFilters(string testFilters) =>
-			testFilters?.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)).ToArray()
-			?? new string[] { };
+		public static Type GetClusterFixtureType(ITypeInfo testClass) =>
+			GetPartitionFixtureType(testClass, typeof(IClusterFixture<>));
 
-		private static bool MatchesATestFilter(string test, IReadOnlyCollection testFilters)
-		{
-			if (testFilters.Count == 0 || string.IsNullOrWhiteSpace(test)) return true;
-			return testFilters
-				.Any(filter => test.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0);
-		}
-
-		private bool MatchesClusterFilter(string cluster)
-		{
-			if (string.IsNullOrWhiteSpace(cluster) || string.IsNullOrWhiteSpace(ClusterFilter)) return true;
-			return ClusterFilter
-				.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
-				.Select(c => c.Trim())
-				.Any(c => cluster.IndexOf(c, StringComparison.OrdinalIgnoreCase) >= 0);
-		}
-
-		private IEphemeralCluster ClusterFixture(ITestClass testMethodTestClass)
-		{
-			var clusterType = GetClusterForClass(testMethodTestClass.Class);
-			if (clusterType == null) return null;
 
-			if (_assemblyFixtureMappings.TryGetValue(clusterType, out var cluster)) return cluster;
-			Aggregator.Run(() =>
-			{
-				var o = Activator.CreateInstance(clusterType);
-				cluster = o as IEphemeralCluster;
-			});
-			_assemblyFixtureMappings.Add(clusterType, cluster);
-			return cluster;
-		}
-
-		public static bool IsAnIntegrationTestClusterType(Type type) =>
-			typeof(XunitClusterBase).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())
-			|| IsSubclassOfRawGeneric(typeof(XunitClusterBase<>), type);
-
-		public static Type GetClusterForClass(ITypeInfo testClass) =>
-			GetClusterFromClassClusterFixture(testClass) ?? GetClusterFromIntegrationAttribute(testClass);
-
-		private static Type GetClusterFromClassClusterFixture(ITypeInfo testClass) => (
-			from i in testClass.Interfaces
-			where i.IsGenericType
-			from a in i.GetGenericArguments()
-			select a.ToRuntimeType()
-		).FirstOrDefault(IsAnIntegrationTestClusterType);
-
-		private static Type GetClusterFromIntegrationAttribute(ITypeInfo testClass) =>
-			testClass.GetCustomAttributes(typeof(IntegrationTestClusterAttribute))
-				.FirstOrDefault()?.GetNamedArgument(nameof(IntegrationTestClusterAttribute.ClusterType));
-
-		private static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
-		{
-			while (toCheck != null && toCheck != typeof(object))
-			{
-				var cur = toCheck.GetTypeInfo().IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
-				if (generic == cur) return true;
-
-				toCheck = toCheck.GetTypeInfo().BaseType;
-			}
-
-			return false;
-		}
-
-		private class GroupedByCluster
-		{
-			public IEphemeralCluster Cluster { get; set; }
-			public ITestCollection Collection { get; set; }
-			public List TestCases { get; set; }
-		}
 	}
 }
diff --git a/src/Elastic.Elasticsearch.Xunit/Sdk/TestCollectionRunner.cs b/src/Elastic.Elasticsearch.Xunit/Sdk/TestCollectionRunner.cs
deleted file mode 100644
index 94083cb..0000000
--- a/src/Elastic.Elasticsearch.Xunit/Sdk/TestCollectionRunner.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Xunit.Abstractions;
-using Xunit.Sdk;
-
-namespace Elastic.Elasticsearch.Xunit.Sdk
-{
-	internal class TestCollectionRunner : XunitTestCollectionRunner
-	{
-		private readonly Dictionary _assemblyFixtureMappings;
-		private readonly IMessageSink _diagnosticMessageSink;
-
-		public TestCollectionRunner(Dictionary assemblyFixtureMappings,
-			ITestCollection testCollection,
-			IEnumerable testCases,
-			IMessageSink diagnosticMessageSink,
-			IMessageBus messageBus,
-			ITestCaseOrderer testCaseOrderer,
-			ExceptionAggregator aggregator,
-			CancellationTokenSource cancellationTokenSource)
-			: base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator,
-				cancellationTokenSource)
-		{
-			_assemblyFixtureMappings = assemblyFixtureMappings;
-			_diagnosticMessageSink = diagnosticMessageSink;
-		}
-
-		protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class,
-			IEnumerable testCases)
-		{
-			// whats this doing exactly??
-			var combinedFixtures = new Dictionary(_assemblyFixtureMappings);
-			foreach (var kvp in CollectionFixtureMappings)
-				combinedFixtures[kvp.Key] = kvp.Value;
-
-			// We've done everything we need, so hand back off to default Xunit implementation for class runner
-			return new XunitTestClassRunner(testClass, @class, testCases, _diagnosticMessageSink, MessageBus,
-					TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, combinedFixtures)
-				.RunAsync();
-		}
-	}
-}
diff --git a/src/Elastic.Elasticsearch.Xunit/Sdk/TestFrameworkExecutor.cs b/src/Elastic.Elasticsearch.Xunit/Sdk/TestFrameworkExecutor.cs
deleted file mode 100644
index ab2fcea..0000000
--- a/src/Elastic.Elasticsearch.Xunit/Sdk/TestFrameworkExecutor.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using Elastic.Elasticsearch.Managed;
-using Xunit.Abstractions;
-using Xunit.Sdk;
-
-namespace Elastic.Elasticsearch.Xunit.Sdk
-{
-	internal class TestFrameworkExecutor : XunitTestFrameworkExecutor
-	{
-		public TestFrameworkExecutor(AssemblyName a, ISourceInformationProvider sip, IMessageSink d) : base(a, sip, d)
-		{
-		}
-
-		public ElasticXunitRunOptions Options { get; set; }
-
-		public override void RunAll(IMessageSink executionMessageSink, ITestFrameworkDiscoveryOptions discoveryOptions,
-			ITestFrameworkExecutionOptions executionOptions)
-		{
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.Version), Options.Version);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests), Options.RunIntegrationTests);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.IntegrationTestsMayUseAlreadyRunningNode),
-				Options.IntegrationTestsMayUseAlreadyRunningNode);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.RunUnitTests), Options.RunUnitTests);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.TestFilter), Options.TestFilter);
-			discoveryOptions.SetValue(nameof(ElasticXunitRunOptions.ClusterFilter), Options.ClusterFilter);
-
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.Version), Options.Version);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests), Options.RunIntegrationTests);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.IntegrationTestsMayUseAlreadyRunningNode),
-				Options.IntegrationTestsMayUseAlreadyRunningNode);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.RunUnitTests), Options.RunUnitTests);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.TestFilter), Options.TestFilter);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.ClusterFilter), Options.ClusterFilter);
-
-			base.RunAll(executionMessageSink, discoveryOptions, executionOptions);
-		}
-
-
-		public override void RunTests(IEnumerable testCases, IMessageSink executionMessageSink,
-			ITestFrameworkExecutionOptions executionOptions)
-		{
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.Version), Options.Version);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests), Options.RunIntegrationTests);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.IntegrationTestsMayUseAlreadyRunningNode),
-				Options.IntegrationTestsMayUseAlreadyRunningNode);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.RunUnitTests), Options.RunUnitTests);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.TestFilter), Options.TestFilter);
-			executionOptions.SetValue(nameof(ElasticXunitRunOptions.ClusterFilter), Options.ClusterFilter);
-			base.RunTests(testCases, executionMessageSink, executionOptions);
-		}
-
-		protected override async void RunTestCases(IEnumerable testCases, IMessageSink sink,
-			ITestFrameworkExecutionOptions options)
-		{
-			options.SetValue(nameof(ElasticXunitRunOptions.Version), Options.Version);
-			options.SetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests), Options.RunIntegrationTests);
-			options.SetValue(nameof(ElasticXunitRunOptions.IntegrationTestsMayUseAlreadyRunningNode),
-				Options.IntegrationTestsMayUseAlreadyRunningNode);
-			options.SetValue(nameof(ElasticXunitRunOptions.RunUnitTests), Options.RunUnitTests);
-			options.SetValue(nameof(ElasticXunitRunOptions.TestFilter), Options.TestFilter);
-			options.SetValue(nameof(ElasticXunitRunOptions.ClusterFilter), Options.ClusterFilter);
-			try
-			{
-				using (var runner =
-					new TestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, sink, options))
-				{
-					Options.OnBeforeTestsRun();
-					await runner.RunAsync().ConfigureAwait(false);
-					Options.OnTestsFinished(runner.ClusterTotals, runner.FailedCollections);
-				}
-			}
-			catch (Exception e)
-			{
-				if (e is ElasticsearchCleanExitException || e is AggregateException ae &&
-					ae.Flatten().InnerException is ElasticsearchCleanExitException)
-					sink.OnMessage(new TestAssemblyCleanupFailure(Enumerable.Empty(), TestAssembly,
-						new ElasticsearchCleanExitException("Node failed to start", e)));
-				else
-					sink.OnMessage(new TestAssemblyCleanupFailure(Enumerable.Empty(), TestAssembly, e));
-				throw;
-			}
-		}
-	}
-}
diff --git a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/ElasticTestCaseDiscoverer.cs b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/ElasticTestCaseDiscoverer.cs
index d259000..406795b 100644
--- a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/ElasticTestCaseDiscoverer.cs
+++ b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/ElasticTestCaseDiscoverer.cs
@@ -22,8 +22,11 @@ protected ElasticTestCaseDiscoverer(IMessageSink diagnosticMessageSink) =>
 			DiagnosticMessageSink = diagnosticMessageSink;
 
 		/// 
-		public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions,
-			ITestMethod testMethod, IAttributeInfo factAttribute) =>
+		public IEnumerable Discover(
+			ITestFrameworkDiscoveryOptions discoveryOptions,
+			ITestMethod testMethod,
+			IAttributeInfo factAttribute
+		) =>
 			SkipMethod(discoveryOptions, testMethod, out var skipReason)
 				? string.IsNullOrEmpty(skipReason)
 					? new IXunitTestCase[] { }
@@ -47,17 +50,6 @@ protected virtual bool SkipMethod(ITestFrameworkDiscoveryOptions discoveryOption
 			return false;
 		}
 
-		protected static TValue GetAttribute(ITestMethod testMethod, string propertyName)
-			where TAttribute : Attribute
-		{
-			var classAttributes = testMethod.TestClass.Class.GetCustomAttributes(typeof(TAttribute)) ??
-			                      Enumerable.Empty();
-			var methodAttributes = testMethod.Method.GetCustomAttributes(typeof(TAttribute)) ??
-			                       Enumerable.Empty();
-			var attribute = classAttributes.Concat(methodAttributes).FirstOrDefault();
-			return attribute == null ? default(TValue) : attribute.GetNamedArgument(propertyName);
-		}
-
 		protected static IList GetAttributes(ITestMethod testMethod)
 			where TAttribute : Attribute
 		{
@@ -67,16 +59,5 @@ protected static IList GetAttributes(ITestMethod tes
 			                       Enumerable.Empty();
 			return classAttributes.Concat(methodAttributes).ToList();
 		}
-
-		protected static IEnumerable GetAttributes(ITestMethod testMethod,
-			string propertyName)
-			where TAttribute : Attribute
-		{
-			var classAttributes = testMethod.TestClass.Class.GetCustomAttributes(typeof(TAttribute));
-			var methodAttributes = testMethod.Method.GetCustomAttributes(typeof(TAttribute));
-			return classAttributes
-				.Concat(methodAttributes)
-				.Select(a => a.GetNamedArgument(propertyName));
-		}
 	}
 }
diff --git a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestClusterAttribute.cs b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestClusterAttribute.cs
deleted file mode 100644
index 1ff468a..0000000
--- a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestClusterAttribute.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using System;
-using Elastic.Elasticsearch.Xunit.Sdk;
-
-namespace Elastic.Elasticsearch.Xunit.XunitPlumbing
-{
-	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
-	public class IntegrationTestClusterAttribute : Attribute
-	{
-		public IntegrationTestClusterAttribute(Type clusterType)
-		{
-			if (!TestAssemblyRunner.IsAnIntegrationTestClusterType(clusterType))
-				throw new ArgumentException(
-					$"Cluster must be subclass of {nameof(XunitClusterBase)} or {nameof(XunitClusterBase)}<>");
-			ClusterType = clusterType;
-		}
-
-		public Type ClusterType { get; }
-	}
-}
diff --git a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestDiscoverer.cs b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestDiscoverer.cs
index 69cbad4..e347be2 100644
--- a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestDiscoverer.cs
+++ b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/IntegrationTestDiscoverer.cs
@@ -34,11 +34,11 @@ public abstract class SkipTestAttributeBase : Attribute
 	/// 
 	///     An Xunit integration test
 	/// 
-	[XunitTestCaseDiscoverer("Elastic.Elasticsearch.Xunit.XunitPlumbing.IntegrationTestDiscoverer",
-		"Elastic.Elasticsearch.Xunit")]
-	public class I : FactAttribute
-	{
-	}
+	[XunitTestCaseDiscoverer(
+		"Elastic.Elasticsearch.Xunit.XunitPlumbing.IntegrationTestDiscoverer",
+		"Elastic.Elasticsearch.Xunit"
+	)]
+	public class I : FactAttribute { }
 
 	/// 
 	///     A test discoverer used to discover integration tests cases attached
@@ -51,19 +51,22 @@ public IntegrationTestDiscoverer(IMessageSink diagnosticMessageSink) : base(diag
 		}
 
 		/// 
-		protected override bool SkipMethod(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod,
-			out string skipReason)
+		protected override bool SkipMethod(
+			ITestFrameworkDiscoveryOptions discoveryOptions,
+			ITestMethod testMethod,
+			out string skipReason
+		)
 		{
 			skipReason = null;
 			var runIntegrationTests =
 				discoveryOptions.GetValue(nameof(ElasticXunitRunOptions.RunIntegrationTests));
 			if (!runIntegrationTests) return true;
 
-			var cluster = TestAssemblyRunner.GetClusterForClass(testMethod.TestClass.Class);
+			var cluster = TestAssemblyRunner.GetClusterFixtureType(testMethod.TestClass.Class);
 			if (cluster == null)
 			{
 				skipReason +=
-					$"{testMethod.TestClass.Class.Name} does not define a cluster through IClusterFixture or {nameof(IntegrationTestClusterAttribute)}";
+					$"{testMethod.TestClass.Class.Name} does not define a cluster through IClusterFixture";
 				return true;
 			}
 
@@ -71,7 +74,7 @@ protected override bool SkipMethod(ITestFrameworkDiscoveryOptions discoveryOptio
 				discoveryOptions.GetValue(nameof(ElasticXunitRunOptions.Version));
 
 			// Skip if the version we are testing against is attributed to be skipped do not run the test nameof(SkipVersionAttribute.Ranges)
-			var skipVersionAttribute = Enumerable.FirstOrDefault(GetAttributes(testMethod));
+			var skipVersionAttribute = GetAttributes(testMethod).FirstOrDefault();
 			if (skipVersionAttribute != null)
 			{
 				var skipVersionRanges =
diff --git a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/SkippingTestCase.cs b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/SkippingTestCase.cs
index 2cd54a6..9cb7d21 100644
--- a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/SkippingTestCase.cs
+++ b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/SkippingTestCase.cs
@@ -12,9 +12,8 @@ namespace Elastic.Elasticsearch.Xunit.XunitPlumbing
 	public class SkippingTestCase : TestMethodTestCase, IXunitTestCase
 	{
 		/// Used for de-serialization.
-		public SkippingTestCase()
-		{
-		}
+		// ReSharper disable once UnusedMember.Global
+		public SkippingTestCase() { }
 
 		/// 
 		///     Initializes a new instance of the  class.
diff --git a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/UnitTestDiscoverer.cs b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/UnitTestDiscoverer.cs
index 1f27ae0..954db69 100644
--- a/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/UnitTestDiscoverer.cs
+++ b/src/Elastic.Elasticsearch.Xunit/XunitPlumbing/UnitTestDiscoverer.cs
@@ -12,8 +12,10 @@ namespace Elastic.Elasticsearch.Xunit.XunitPlumbing
 	/// 
 	///     An Xunit unit test
 	/// 
-	[XunitTestCaseDiscoverer("Elastic.Elasticsearch.Xunit.XunitPlumbing.UnitTestDiscoverer",
-		"Elastic.Elasticsearch.Xunit")]
+	[XunitTestCaseDiscoverer(
+		"Elastic.Elasticsearch.Xunit.XunitPlumbing.UnitTestDiscoverer",
+		"Elastic.Elasticsearch.Xunit"
+	)]
 	public class U : FactAttribute
 	{
 	}
@@ -29,7 +31,9 @@ public UnitTestDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticM
 		}
 
 		/// 
-		protected override bool SkipMethod(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod,
+		protected override bool SkipMethod(
+			ITestFrameworkDiscoveryOptions discoveryOptions,
+			ITestMethod testMethod,
 			out string skipReason)
 		{
 			skipReason = null;