Add AssemblyFixture to our test infra
This is a feature that we're using in Templates and Blazor E2E tests to manage selenium.
It's a general purpose kind of thing, so it makes sense to make it more general. This requires using the
`[assembly: TestFramework()]`.
Also fixed a bug here where this feature broke collection fixtures.
\n\nCommit migrated from 208d44a985
This commit is contained in:
parent
b1987c75cb
commit
aadc979baf
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
public class AspNetTestAssemblyRunner : XunitTestAssemblyRunner
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Type, object> _assemblyFixtureMappings = new Dictionary<Type, object>();
|
||||||
|
|
||||||
|
public AspNetTestAssemblyRunner(
|
||||||
|
ITestAssembly testAssembly,
|
||||||
|
IEnumerable<IXunitTestCase> testCases,
|
||||||
|
IMessageSink diagnosticMessageSink,
|
||||||
|
IMessageSink executionMessageSink,
|
||||||
|
ITestFrameworkExecutionOptions executionOptions)
|
||||||
|
: base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AfterTestAssemblyStartingAsync()
|
||||||
|
{
|
||||||
|
await base.AfterTestAssemblyStartingAsync();
|
||||||
|
|
||||||
|
// Find all the AssemblyFixtureAttributes on the test assembly
|
||||||
|
Aggregator.Run(() =>
|
||||||
|
{
|
||||||
|
var fixturesAttributes = ((IReflectionAssemblyInfo)TestAssembly.Assembly)
|
||||||
|
.Assembly
|
||||||
|
.GetCustomAttributes(typeof(AssemblyFixtureAttribute), false)
|
||||||
|
.Cast<AssemblyFixtureAttribute>()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Instantiate all the fixtures
|
||||||
|
foreach (var fixtureAttribute in fixturesAttributes)
|
||||||
|
{
|
||||||
|
var ctorWithDiagnostics = fixtureAttribute.FixtureType.GetConstructor(new[] { typeof(IMessageSink) });
|
||||||
|
if (ctorWithDiagnostics != null)
|
||||||
|
{
|
||||||
|
_assemblyFixtureMappings[fixtureAttribute.FixtureType] = Activator.CreateInstance(fixtureAttribute.FixtureType, DiagnosticMessageSink);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_assemblyFixtureMappings[fixtureAttribute.FixtureType] = Activator.CreateInstance(fixtureAttribute.FixtureType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task BeforeTestAssemblyFinishedAsync()
|
||||||
|
{
|
||||||
|
// Dispose fixtures
|
||||||
|
foreach (var disposable in _assemblyFixtureMappings.Values.OfType<IDisposable>())
|
||||||
|
{
|
||||||
|
Aggregator.Run(disposable.Dispose);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.BeforeTestAssemblyFinishedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<RunSummary> RunTestCollectionAsync(
|
||||||
|
IMessageBus messageBus,
|
||||||
|
ITestCollection testCollection,
|
||||||
|
IEnumerable<IXunitTestCase> testCases,
|
||||||
|
CancellationTokenSource cancellationTokenSource)
|
||||||
|
=> new AspNetTestCollectionRunner(
|
||||||
|
_assemblyFixtureMappings,
|
||||||
|
testCollection,
|
||||||
|
testCases,
|
||||||
|
DiagnosticMessageSink,
|
||||||
|
messageBus,
|
||||||
|
TestCaseOrderer,
|
||||||
|
new ExceptionAggregator(Aggregator),
|
||||||
|
cancellationTokenSource).RunAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
public class AspNetTestCollectionRunner : XunitTestCollectionRunner
|
||||||
|
{
|
||||||
|
private readonly IDictionary<Type, object> _assemblyFixtureMappings;
|
||||||
|
private readonly IMessageSink _diagnosticMessageSink;
|
||||||
|
|
||||||
|
public AspNetTestCollectionRunner(
|
||||||
|
Dictionary<Type, object> assemblyFixtureMappings,
|
||||||
|
ITestCollection testCollection,
|
||||||
|
IEnumerable<IXunitTestCase> 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 async Task AfterTestCollectionStartingAsync()
|
||||||
|
{
|
||||||
|
await base.AfterTestCollectionStartingAsync();
|
||||||
|
|
||||||
|
// note: We pass the assembly fixtures into the runner as ICollectionFixture<> - this seems to work OK without any
|
||||||
|
// drawbacks. It's reasonable that we could add IAssemblyFixture<> and related plumbing if it ever became required.
|
||||||
|
//
|
||||||
|
// The reason for assembly fixture is when we want to start/stop something as the project scope - tests can only be
|
||||||
|
// in one test collection at a time.
|
||||||
|
foreach (var mapping in _assemblyFixtureMappings)
|
||||||
|
{
|
||||||
|
CollectionFixtureMappings.Add(mapping.Key, mapping.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task BeforeTestCollectionFinishedAsync()
|
||||||
|
{
|
||||||
|
// We need to remove the assembly fixtures so they won't get disposed.
|
||||||
|
foreach (var mapping in _assemblyFixtureMappings)
|
||||||
|
{
|
||||||
|
CollectionFixtureMappings.Remove(mapping.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.BeforeTestCollectionFinishedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<RunSummary> RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable<IXunitTestCase> testCases)
|
||||||
|
{
|
||||||
|
var caste = testCases.ToArray();
|
||||||
|
var type = caste.First().GetType();
|
||||||
|
return base.RunTestClassAsync(testClass, @class, testCases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Reflection;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
public class AspNetTestFramework : XunitTestFramework
|
||||||
|
{
|
||||||
|
public AspNetTestFramework(IMessageSink messageSink)
|
||||||
|
: base(messageSink)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
|
||||||
|
=> new AspNetTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
public class AspNetTestFrameworkExecutor : XunitTestFrameworkExecutor
|
||||||
|
{
|
||||||
|
public AspNetTestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink)
|
||||||
|
: base(assemblyName, sourceInformationProvider, diagnosticMessageSink)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async void RunTestCases(IEnumerable<IXunitTestCase> testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions)
|
||||||
|
{
|
||||||
|
using (var assemblyRunner = new AspNetTestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink, executionOptions))
|
||||||
|
{
|
||||||
|
await assemblyRunner.RunAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||||
|
public class AssemblyFixtureAttribute : Attribute
|
||||||
|
{
|
||||||
|
public AssemblyFixtureAttribute(Type fixtureType)
|
||||||
|
{
|
||||||
|
FixtureType = fixtureType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type FixtureType { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
// We include a collection and assembly fixture to verify that they both still work.
|
||||||
|
[Collection("MyCollection")]
|
||||||
|
[TestCaseOrderer("Microsoft.AspNetCore.Testing.AlphabeticalOrderer", "Microsoft.AspNetCore.Testing.Tests")]
|
||||||
|
public class AssemblyFixtureTest
|
||||||
|
{
|
||||||
|
public AssemblyFixtureTest(TestAssemblyFixture assemblyFixture, TestCollectionFixture collectionFixture)
|
||||||
|
{
|
||||||
|
AssemblyFixture = assemblyFixture;
|
||||||
|
CollectionFixture = collectionFixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAssemblyFixture AssemblyFixture { get; }
|
||||||
|
public TestCollectionFixture CollectionFixture { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void A()
|
||||||
|
{
|
||||||
|
Assert.NotNull(AssemblyFixture);
|
||||||
|
Assert.Equal(0, AssemblyFixture.Count);
|
||||||
|
|
||||||
|
Assert.NotNull(CollectionFixture);
|
||||||
|
Assert.Equal(0, CollectionFixture.Count);
|
||||||
|
|
||||||
|
AssemblyFixture.Count++;
|
||||||
|
CollectionFixture.Count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void B()
|
||||||
|
{
|
||||||
|
Assert.Equal(1, AssemblyFixture.Count);
|
||||||
|
Assert.Equal(1, CollectionFixture.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CollectionDefinition("MyCollection", DisableParallelization = true)]
|
||||||
|
public class MyCollection : ICollectionFixture<TestCollectionFixture>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
[assembly: AssemblyFixture(typeof(TestAssemblyFixture))]
|
||||||
|
[assembly: TestFramework("Microsoft.AspNetCore.Testing.AspNetTestFramework", "Microsoft.AspNetCore.Testing")]
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
public class TestAssemblyFixture
|
||||||
|
{
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
public class TestCollectionFixture
|
||||||
|
{
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue