Skip to content

Commit

Permalink
Buckets of XML doc comments, plus made TestXxxRunner classes consistent.
Browse files Browse the repository at this point in the history
  • Loading branch information
bradwilson committed Apr 29, 2014
1 parent 991cf96 commit ddd38e4
Show file tree
Hide file tree
Showing 18 changed files with 597 additions and 174 deletions.
22 changes: 22 additions & 0 deletions src/xunit.core/Sdk/RunSummary.cs
@@ -1,12 +1,34 @@
namespace Xunit.Sdk
{
/// <summary>
/// Represents the statistical summary from a run of one or more tests.
/// </summary>
public class RunSummary
{
/// <summary>
/// The total number of tests run.
/// </summary>
public int Total;

/// <summary>
/// The number of failed tests.
/// </summary>
public int Failed;

/// <summary>
/// The number of skipped tests.
/// </summary>
public int Skipped;

/// <summary>
/// The total time taken to run the tests, in seconds.
/// </summary>
public decimal Time;

/// <summary>
/// Adds a run summary's totals into this run summary.
/// </summary>
/// <param name="other">The run summary to be added.</param>
public void Aggregate(RunSummary other)
{
Total += other.Total;
Expand Down
83 changes: 82 additions & 1 deletion src/xunit.execution/Sdk/ExtensibilityPointFactory.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using Xunit.Abstractions;

namespace Xunit.Sdk
Expand Down Expand Up @@ -33,7 +34,7 @@ public static void Dispose()
}

/// <summary>
/// Gets an instance of the given type, casting it to <see cref="TInterface"/>, using the provided
/// Gets an instance of the given type, casting it to <typeparamref name="TInterface"/>, using the provided
/// constructor arguments. There is a single instance of a given type that is cached and reused,
/// so classes retrieved from this factory must be stateless and thread-safe.
/// </summary>
Expand All @@ -54,6 +55,21 @@ public static IDataDiscoverer GetDataDiscoverer(Type discovererType)
return Get<IDataDiscoverer>(discovererType);
}

/// <summary>
/// Gets a data discoverer, as specified in a reflected <see cref="DataDiscovererAttribute"/>.
/// </summary>
/// <param name="dataDiscovererAttribute">The data discoverer attribute</param>
/// <returns>The data discoverer, if the type is loadable; <c>null</c>, otherwise.</returns>
public static IDataDiscoverer GetDataDiscoverer(IAttributeInfo dataDiscovererAttribute)
{
var args = dataDiscovererAttribute.GetConstructorArguments().Cast<string>().ToList();
var discovererType = Reflector.GetType(args[1], args[0]);
if (discovererType == null)
return null;

return GetDataDiscoverer(discovererType);
}

/// <summary>
/// Gets a test case orderer.
/// </summary>
Expand All @@ -62,6 +78,21 @@ public static ITestCaseOrderer GetTestCaseOrderer(Type ordererType)
return Get<ITestCaseOrderer>(ordererType);
}

/// <summary>
/// Gets a test case orderer, as specified in a reflected <see cref="TestCaseOrdererAttribute"/>.
/// </summary>
/// <param name="testCaseOrdererAttribute">The test case orderer attribute.</param>
/// <returns>The test case orderer, if the type is loadable; <c>null</c>, otherwise.</returns>
public static ITestCaseOrderer GetTestCaseOrderer(IAttributeInfo testCaseOrdererAttribute)
{
var args = testCaseOrdererAttribute.GetConstructorArguments().Cast<string>().ToList();
var ordererType = Reflector.GetType(args[1], args[0]);
if (ordererType == null)
return null;

return GetTestCaseOrderer(ordererType);
}

/// <summary>
/// Gets a trait discoverer.
/// </summary>
Expand All @@ -70,6 +101,21 @@ public static ITraitDiscoverer GetTraitDiscoverer(Type discovererType)
return Get<ITraitDiscoverer>(discovererType);
}

/// <summary>
/// Gets a trait discoverer, as specified in a reflected <see cref="TraitDiscovererAttribute"/>.
/// </summary>
/// <param name="traitDiscovererAttribute">The trait discoverer attribute.</param>
/// <returns>The trait discoverer, if the type is loadable; <c>null</c>, otherwise.</returns>
public static ITraitDiscoverer GetTraitDiscoverer(IAttributeInfo traitDiscovererAttribute)
{
var args = traitDiscovererAttribute.GetConstructorArguments().Cast<string>().ToList();
var discovererType = Reflector.GetType(args[1], args[0]);
if (discovererType == null)
return null;

return GetTraitDiscoverer(discovererType);
}

/// <summary>
/// Gets an xUnit.net v2 test discoverer.
/// </summary>
Expand All @@ -85,5 +131,40 @@ public static IXunitTestCollectionFactory GetXunitTestCollectionFactory(Type fac
{
return Get<IXunitTestCollectionFactory>(factoryType, new[] { assemblyInfo });
}

/// <summary>
/// Gets an xUnit.net v2 test collection factory, as specified in a reflected <see cref="CollectionBehaviorAttribute"/>.
/// </summary>
/// <param name="collectionBehaviorAttribute">The collection behavior attribute.</param>
/// <param name="assemblyInfo">The test assembly.</param>
/// <returns>The collection factory.</returns>
public static IXunitTestCollectionFactory GetXunitTestCollectionFactory(IAttributeInfo collectionBehaviorAttribute, IAssemblyInfo assemblyInfo)
{
return GetXunitTestCollectionFactory(GetTestCollectionFactoryType(collectionBehaviorAttribute), assemblyInfo);
}

static Type GetTestCollectionFactoryType(IAttributeInfo collectionBehaviorAttribute)
{
if (collectionBehaviorAttribute == null)
return typeof(CollectionPerClassTestCollectionFactory);

var ctorArgs = collectionBehaviorAttribute.GetConstructorArguments().ToList();
if (ctorArgs.Count == 0)
return typeof(CollectionPerClassTestCollectionFactory);

if (ctorArgs.Count == 1)
{
if ((CollectionBehavior)ctorArgs[0] == CollectionBehavior.CollectionPerAssembly)
return typeof(CollectionPerAssemblyTestCollectionFactory);

return typeof(CollectionPerClassTestCollectionFactory);
}

var result = Reflector.GetType((string)ctorArgs[1], (string)ctorArgs[0]);
if (result == null || !typeof(IXunitTestCollectionFactory).IsAssignableFrom(result) || result.GetConstructor(new[] { typeof(IAssemblyInfo) }) == null)
return typeof(CollectionPerClassTestCollectionFactory);

return result;
}
}
}
77 changes: 71 additions & 6 deletions src/xunit.execution/Sdk/Frameworks/Runners/TestAssemblyRunner.cs
Expand Up @@ -9,11 +9,24 @@

namespace Xunit.Sdk
{
/// <summary>
/// A base class that provides default behavior when running tests in an assembly. It groups the tests
/// by test collection, and then runs the individual test collections.
/// </summary>
/// <typeparam name="TTestCase">The type of the test case used by the test framework. Must
/// derive from <see cref="ITestCase"/>.</typeparam>
public abstract class TestAssemblyRunner<TTestCase> : IDisposable
where TTestCase : ITestCase
{
/// <summary>
/// Initializes a new instance of the <see cref="TestAssemblyRunner{TTestCase}"/> class.
/// </summary>
/// <param name="assemblyInfo">The assembly that contains the tests to be run.</param>
/// <param name="testCases">The test cases to be run.</param>
/// <param name="messageSink">The message sink to report run status to.</param>
/// <param name="executionOptions">The user's requested execution options.</param>
public TestAssemblyRunner(IAssemblyInfo assemblyInfo,
IEnumerable<ITestCase> testCases,
IEnumerable<TTestCase> testCases,
IMessageSink messageSink,
ITestFrameworkOptions executionOptions)
{
Expand All @@ -30,29 +43,59 @@ public abstract class TestAssemblyRunner<TTestCase> : IDisposable
/// </summary>
protected string AssemblyFileName { get; private set; }

/// <summary>
/// Gets or sets the assembly that contains the tests to be run.
/// </summary>
protected IAssemblyInfo AssemblyInfo { get; set; }

/// <summary>
/// Gets or sets the user's requested execution options.
/// </summary>
protected ITestFrameworkOptions ExecutionOptions { get; set; }

/// <summary>
/// Gets or sets the message sink to report run status to.
/// </summary>
protected IMessageSink MessageSink { get; set; }

protected IEnumerable<ITestCase> TestCases { get; set; }

/// <summary>
/// Gets or sets the test case orderer that will be used to decide how to order the test.
/// </summary>
protected ITestCaseOrderer TestCaseOrderer { get; set; }

/// <summary>
/// Gets or sets the test cases to be run.
/// </summary>
protected IEnumerable<TTestCase> TestCases { get; set; }

/// <inheritdoc/>
public virtual void Dispose() { }

/// <summary>
/// Override this to provide the display name for the test framework (f.e., "xUnit.net 2.0").
/// This value is placed into <see cref="ITestAssemblyStarting.TestFrameworkDisplayName"/>.
/// </summary>
protected abstract string GetTestFrameworkDisplayName();

/// <summary>
/// Override this to provide the environment information (f.e., "32-bit .NET 4.0"). This value is
/// placed into <see cref="ITestAssemblyStarting.TestEnvironment"/>.
/// </summary>
protected abstract string GetTestFrameworkEnvironment();

/// <summary>
/// Override this method to run code just before the test assembly is run.
/// </summary>
protected virtual void OnAssemblyStarting() { }

/// <summary>
/// Override this method to run code just after the test assembly run has finished.
/// </summary>
protected virtual void OnAssemblyFinished() { }

/// <summary>
/// Creates the message bus to be used for test execution. By default, it inspects
/// the options for the <see cref="TestOptionsNames.Execution.SynchronnousMessageReporting"/>
/// the options for the <see cref="TestOptionsNames.Execution.SynchronousMessageReporting"/>
/// flag, and if present, creates a message bus that ensures all messages are delivered
/// on the same thread.
/// </summary>
Expand All @@ -65,6 +108,10 @@ protected virtual IMessageBus CreateMessageBus()
return new MessageBus(MessageSink);
}

/// <summary>
/// Runs the tests in the test assembly.
/// </summary>
/// <returns>Returns summary information about the tests that were run.</returns>
public async Task<RunSummary> RunAsync()
{
OnAssemblyStarting();
Expand Down Expand Up @@ -94,24 +141,42 @@ public async Task<RunSummary> RunAsync()
{
messageBus.QueueMessage(new TestAssemblyFinished(AssemblyInfo, totalSummary.Time, totalSummary.Total, totalSummary.Failed, totalSummary.Skipped));
Directory.SetCurrentDirectory(currentDirectory);

OnAssemblyFinished();
}
}

OnAssemblyFinished();

return totalSummary;
}

/// <summary>
/// Runs the list of test collections. By default, groups the tests by collection and runs them synchronously.
/// </summary>
/// <param name="messageBus">The message bus to report run status to.</param>
/// <param name="cancellationTokenSource">The task cancellation token source, used to cancel the test run.</param>
/// <returns>Returns summary information about the tests that were run.</returns>
protected virtual async Task<RunSummary> RunTestCollectionsAsync(IMessageBus messageBus, CancellationTokenSource cancellationTokenSource)
{
var summary = new RunSummary();

foreach (var collectionGroup in TestCases.Cast<TTestCase>().GroupBy(tc => tc.TestCollection, TestCollectionComparer.Instance))
{
summary.Aggregate(await RunTestCollectionAsync(messageBus, collectionGroup.Key, collectionGroup, cancellationTokenSource));
if (cancellationTokenSource.IsCancellationRequested)
break;
}

return summary;
}

/// <summary>
/// Override this method to run the tests in an individual test collection.
/// </summary>
/// <param name="messageBus">The message bus to report run status to.</param>
/// <param name="testCollection">The test collection that is being run.</param>
/// <param name="testCases">The test cases to be run.</param>
/// <param name="cancellationTokenSource">The task cancellation token source, used to cancel the test run.</param>
/// <returns>Returns summary information about the tests that were run.</returns>
protected abstract Task<RunSummary> RunTestCollectionAsync(IMessageBus messageBus, ITestCollection testCollection, IEnumerable<TTestCase> testCases, CancellationTokenSource cancellationTokenSource);
}
}

0 comments on commit ddd38e4

Please sign in to comment.