зеркало из
1
0
Форкнуть 0

Add functionality to run multiple assemblies

This commit is contained in:
Chris Maddock 2016-10-22 16:14:07 +01:00
Родитель 71f5408a27
Коммит c2fd1434e9
9 изменённых файлов: 257 добавлений и 107 удалений

Просмотреть файл

@ -1,6 +1,6 @@
{
"projects": [ "src", "test" ],
"sdk": {
"version": "1.0.0-preview2-003121"
"version": "1.0.0-preview2-003131"
}
}

Просмотреть файл

@ -35,23 +35,19 @@ namespace NUnit.Engine
/// </summary>
public class NUnitPortableDriver
{
const string LOAD_MESSAGE = "Method called without calling Load first";
const string INVALID_FRAMEWORK_MESSAGE = "Running tests against this version of the framework using this driver is not supported. Please update NUnit.Framework to the latest version.";
internal const string INVALID_FRAMEWORK_MESSAGE = "Running tests against this version of the framework using this driver is not supported. Please update NUnit.Framework to the latest version.";
private const string LOAD_MESSAGE = "Method called without loading any assemblies";
private const string CONTROLLER_TYPE = "NUnit.Framework.Api.FrameworkController";
private const string LOAD_METHOD = "LoadTests";
private const string EXPLORE_METHOD = "ExploreTests";
private const string COUNT_METHOD = "CountTests";
private const string RUN_METHOD = "RunTests";
private const string RUN_ASYNC_METHOD = "RunTests";
private const string STOP_RUN_METHOD = "StopRun";
static readonly string CONTROLLER_TYPE = "NUnit.Framework.Api.FrameworkController";
static readonly string LOAD_METHOD = "LoadTests";
static readonly string EXPLORE_METHOD = "ExploreTests";
static readonly string COUNT_METHOD = "CountTests";
static readonly string RUN_METHOD = "RunTests";
static readonly string RUN_ASYNC_METHOD = "RunTests";
static readonly string STOP_RUN_METHOD = "StopRun";
static ILogger log = InternalTrace.GetLogger("NUnit3PortableDriver");
Assembly _testAssembly;
Assembly _frameworkAssembly;
object _frameworkController;
Type _frameworkControllerType;
private static readonly ILogger log = InternalTrace.GetLogger("NUnit3PortableDriver");
private readonly List<TestAssemblyWrapper> _testWrappers = new List<TestAssemblyWrapper>();
/// <summary>
/// An id prefix that will be passed to the test framework and used as part of the
@ -69,17 +65,15 @@ namespace NUnit.Engine
public string Load(Assembly frameworkAssembly, Assembly testAssembly, IDictionary<string, object> settings)
{
var idPrefix = string.IsNullOrEmpty(ID) ? "" : ID + "-";
_frameworkAssembly = frameworkAssembly;
_testAssembly = testAssembly;
_frameworkController = CreateObject(CONTROLLER_TYPE, testAssembly, idPrefix, settings);
if (_frameworkController == null)
var frameworkController = CreateObject(CONTROLLER_TYPE, frameworkAssembly, testAssembly, idPrefix, settings);
if (frameworkController == null)
throw new NUnitPortableDriverException(INVALID_FRAMEWORK_MESSAGE);
_frameworkControllerType = _frameworkController.GetType();
var testWrapper = new TestAssemblyWrapper(testAssembly, frameworkController);
_testWrappers.Add(testWrapper);
log.Info("Loading {0} - see separate log file", _testAssembly.FullName);
return ExecuteMethod(LOAD_METHOD) as string;
log.Info("Loading {0} - see separate log file", testAssembly.FullName);
return testWrapper.ExecuteMethod(LOAD_METHOD) as string;
}
/// <summary>
@ -89,9 +83,18 @@ namespace NUnit.Engine
/// <returns>The number of test cases</returns>
public int CountTestCases(string filter)
{
CheckLoadWasCalled();
object count = ExecuteMethod(COUNT_METHOD, filter);
return count != null ? (int)count : 0;
CheckAssembliesLoaded();
var count = 0;
foreach (var wrapper in _testWrappers)
{
object assemblyCount = wrapper.ExecuteMethod(COUNT_METHOD, filter);
if (assemblyCount is int)
count += (int)assemblyCount;
}
return count;
}
/// <summary>
@ -102,9 +105,11 @@ namespace NUnit.Engine
/// <returns>An Xml string representing the result</returns>
public string Run(Action<string> callback, string filter)
{
CheckLoadWasCalled();
log.Info("Running {0} - see separate log file", _testAssembly.FullName);
return ExecuteMethod(RUN_METHOD, new[] { typeof(Action<string>), typeof(string) }, callback, filter) as string;
CheckAssembliesLoaded();
Func<TestAssemblyWrapper, string> runTestsAction =
p => p.ExecuteMethod(RUN_METHOD, new[] {typeof(Action<string>), typeof(string)}, callback, filter) as string;
return SummarizeResults("Running", runTestsAction);
}
/// <summary>
@ -114,18 +119,23 @@ namespace NUnit.Engine
/// <param name="filter">A filter that controls which tests are executed</param>
public void RunAsync(Action<string> callback, string filter)
{
CheckLoadWasCalled();
log.Info("Running {0} - see separate log file", _testAssembly.FullName);
ExecuteMethod(RUN_ASYNC_METHOD, new[] { typeof(Action<string>), typeof(string) }, callback, filter);
CheckAssembliesLoaded();
foreach (var assembly in _testWrappers)
{
log.Info("Running {0} - see separate log file", assembly.FullName);
assembly.ExecuteMethod(RUN_ASYNC_METHOD, new[] { typeof(Action<string>), typeof(string) }, callback, filter);
}
}
/// <summary>
/// Cancel the ongoing test run. If no test is running, the call is ignored.
/// Cancel the ongoing test run. If no test is running, the call is ignored.
/// </summary>
/// <param name="force">If true, cancel any ongoing test threads, otherwise wait for them to complete.</param>
public void StopRun(bool force)
{
ExecuteMethod(STOP_RUN_METHOD, force);
foreach (var assembly in _testWrappers)
assembly.ExecuteMethod(STOP_RUN_METHOD, force);
}
/// <summary>
@ -135,52 +145,43 @@ namespace NUnit.Engine
/// <returns>An Xml string representing the tests</returns>
public string Explore(string filter)
{
CheckLoadWasCalled();
CheckAssembliesLoaded();
log.Info("Exploring {0} - see separate log file", _testAssembly.FullName);
return ExecuteMethod(EXPLORE_METHOD, filter) as string;
Func<TestAssemblyWrapper, string> exploreTestsAction = p => p.ExecuteMethod(EXPLORE_METHOD, filter) as string;
return SummarizeResults("Exploring", exploreTestsAction);
}
#region Helper Methods
void CheckLoadWasCalled()
private string SummarizeResults(string logTask, Func<TestAssemblyWrapper, string> testAction)
{
if (_frameworkController == null)
var summary = new ResultSummary();
foreach (var assembly in _testWrappers)
{
log.Info("{0} {1} - see separate log file", logTask, assembly.FullName);
summary.AddResult(testAction(assembly));
}
return summary.GetTestResults().ToString();
}
private void CheckAssembliesLoaded()
{
if (_testWrappers.Count == 0)
throw new InvalidOperationException(LOAD_MESSAGE);
}
object CreateObject(string typeName, params object[] args)
private static object CreateObject(string typeName, Assembly frameworkAssembly, params object[] args)
{
var typeinfo = _frameworkAssembly.DefinedTypes.FirstOrDefault(t => t.FullName == typeName);
var typeinfo = frameworkAssembly.DefinedTypes.FirstOrDefault(t => t.FullName == typeName);
if (typeinfo == null)
{
log.Error("Could not find type {0}", typeName);
return null;
}
return Activator.CreateInstance(typeinfo.AsType(), args);
}
object ExecuteMethod(string methodName, params object[] args)
{
//var method = _frameworkControllerType.GetMethod(methodName, BindingFlags.Public);
var method = _frameworkControllerType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
return ExecuteMethod(method, args);
}
object ExecuteMethod(string methodName, Type[] ptypes, params object[] args)
{
var method = _frameworkControllerType.GetMethod(methodName, ptypes);
return ExecuteMethod(method, args);
}
object ExecuteMethod(MethodInfo method, params object[] args)
{
if (method == null)
{
throw new NUnitPortableDriverException(INVALID_FRAMEWORK_MESSAGE);
}
return method.Invoke(_frameworkController, args);
}
#endregion
}
}

Просмотреть файл

@ -81,7 +81,6 @@ namespace NUnit.Engine
var test = new XElement("test-run");
test.Add(new XAttribute("id", "0"));
test.Add(new XAttribute("testcasecount", TestCount));
test.Add(new XAttribute("result", Result));
test.Add(new XAttribute("total", TestCount));
test.Add(new XAttribute("passed", PassCount));
test.Add(new XAttribute("failed", FailedCount));
@ -89,6 +88,10 @@ namespace NUnit.Engine
test.Add(new XAttribute("skipped", TotalSkipCount));
test.Add(new XAttribute("asserts", AssertCount));
//Occurs when summarizing explore only
if (Result != null)
test.Add(new XAttribute("result", Result));
test.Add(new XAttribute("portable-engine-version", typeof(ResultSummary).GetTypeInfo().Assembly.GetName().Version.ToString()));
EndTime = DateTime.UtcNow;

Просмотреть файл

@ -0,0 +1,64 @@
// ***********************************************************************
// Copyright (c) 2016 Charlie Poole
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************
using System;
using System.Reflection;
namespace NUnit.Engine
{
internal class TestAssemblyWrapper
{
private readonly Assembly _testAssembly;
private readonly object _frameworkController;
private Type FrameworkControllerType => _frameworkController.GetType();
public string FullName => _testAssembly.FullName;
internal TestAssemblyWrapper(Assembly testAssembly, object frameworkController)
{
_testAssembly = testAssembly;
_frameworkController = frameworkController;
}
internal object ExecuteMethod(string methodName, params object[] args)
{
var method = FrameworkControllerType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
return ExecuteMethod(method, args);
}
internal object ExecuteMethod(string methodName, Type[] ptypes, params object[] args)
{
var method = FrameworkControllerType.GetMethod(methodName, ptypes);
return ExecuteMethod(method, args);
}
private object ExecuteMethod(MethodInfo method, params object[] args)
{
if (method == null)
{
throw new NUnitPortableDriverException(NUnitPortableDriver.INVALID_FRAMEWORK_MESSAGE);
}
return method.Invoke(_frameworkController, args);
}
}
}

Просмотреть файл

@ -136,7 +136,9 @@ namespace NUnit.Engine.Tests.Compatibility
public int MyProperty { get; set; }
[Datapoint]
#pragma warning disable 169
public int field = 1;
#pragma warning restore 169
}
class B : A

Просмотреть файл

@ -0,0 +1,99 @@
// ***********************************************************************
// Copyright (c) 2016 Charlie Poole
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using NUnit.Framework;
using NUnit.Tests.Assemblies;
namespace NUnit.Engine.Tests
{
public class MultipleAssemblyTests
{
const string EMPTY_FILTER = "<filter />";
private readonly IDictionary<string, object> _settings = new Dictionary<string, object>();
private Assembly _mockAssembly;
private Assembly _frameworkAssembly;
private NUnitPortableDriver _driver;
[SetUp]
public void CreateDriver()
{
_mockAssembly = typeof(MockAssembly).GetTypeInfo().Assembly;
_frameworkAssembly = typeof(Assert).GetTypeInfo().Assembly;
_driver = new NUnitPortableDriver();
}
[Test]
public void LoadReturnsSingleNodePerAssembly()
{
for (int i = 0; i < 2; i++)
{
var result = XmlHelper.CreateXElement(_driver.Load(_frameworkAssembly, _mockAssembly, _settings));
Assert.That(result.Name.LocalName, Is.EqualTo("test-suite"));
Assert.That(result.GetAttribute("type"), Is.EqualTo("Assembly"));
Assert.That(result.GetAttribute("runstate"), Is.EqualTo("Runnable"));
}
}
[Test]
public void ExploreTestsAction_AfterLoadMultipleAssemblies_ReturnsAllSuites()
{
LoadMultipleAssemblies();
var result = XmlHelper.CreateXElement(_driver.Explore(EMPTY_FILTER));
Assert.That(result.Name.LocalName, Is.EqualTo("test-run"));
Assert.That(result.Elements(XName.Get("test-suite")).Count(), Is.EqualTo(2));
}
[Test]
public void CountTestsAction_AfterLoadMultipleAssemblies_ReturnsCorrectCount()
{
LoadMultipleAssemblies();
Assert.That(_driver.CountTestCases(EMPTY_FILTER), Is.EqualTo(2 * MockAssembly.Tests));
}
[Test]
public void RunTestsAction_AfterLoadMultipleAssemblies_RunsAllAssemblies()
{
LoadMultipleAssemblies();
var result = XmlHelper.CreateXElement(_driver.Run(null, EMPTY_FILTER));
Assert.That(result.Name.LocalName, Is.EqualTo("test-run"));
var testSuites = result.Elements(XName.Get("test-suite")).ToList();
Assert.That(testSuites, Has.Count.EqualTo(2));
foreach (var suite in testSuites)
Assert.That(suite.GetAttribute("runstate"), Is.EqualTo("Runnable"));
}
private void LoadMultipleAssemblies()
{
_driver.Load(_frameworkAssembly, _mockAssembly, _settings);
_driver.Load(_frameworkAssembly, _mockAssembly, _settings);
}
}
}

Просмотреть файл

@ -26,6 +26,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using System.Reflection;
using System.Xml.Linq;
using NUnit.Tests.Assemblies;
namespace NUnit.Engine.Tests
@ -33,7 +34,7 @@ namespace NUnit.Engine.Tests
public class NUnitPortableDriverTests
{
const string EMPTY_FILTER = "<filter />";
const string LOAD_MESSAGE = "Method called without calling Load first";
const string LOAD_MESSAGE = "Method called without loading any assemblies";
IDictionary<string, object> _settings = new Dictionary<string, object>();
@ -49,14 +50,6 @@ namespace NUnit.Engine.Tests
_driver = new NUnitPortableDriver();
}
#region Construction Test
public void ConstructController_MissingFile_ThrowsArgumentInvalid()
{
Assert.That(new NUnitPortableDriver(), Throws.ArgumentException);
}
#endregion
#region Load
[Test]
public void Load_GoodFile_ReturnsRunnableSuite()
@ -77,12 +70,14 @@ namespace NUnit.Engine.Tests
{
_driver.Load(_frameworkAssembly, _mockAssembly, _settings);
var result = XmlHelper.CreateXElement(_driver.Explore(EMPTY_FILTER));
Assert.That(result.Name.LocalName, Is.EqualTo("test-run"));
Assert.That(result.Name.LocalName, Is.EqualTo("test-suite"));
Assert.That(result.GetAttribute("type"), Is.EqualTo("Assembly"));
Assert.That(result.GetAttribute("runstate"), Is.EqualTo("Runnable"));
Assert.That(result.GetAttribute("testcasecount"), Is.EqualTo(MockAssembly.Tests.ToString()));
Assert.That(result.Elements("test-suite").Count(), Is.GreaterThan(0), "Explore result should have child tests");
var testSuite = result.Element(XName.Get("test-suite"));
Assert.That(testSuite.Name.LocalName, Is.EqualTo("test-suite"));
Assert.That(testSuite.GetAttribute("type"), Is.EqualTo("Assembly"));
Assert.That(testSuite.GetAttribute("runstate"), Is.EqualTo("Runnable"));
Assert.That(testSuite.GetAttribute("testcasecount"), Is.EqualTo(MockAssembly.Tests.ToString()));
Assert.That(testSuite.Elements("test-suite").Count(), Is.GreaterThan(0), "Explore result should have child tests");
}
[Test]
@ -121,17 +116,18 @@ namespace NUnit.Engine.Tests
{
_driver.Load(_frameworkAssembly, _mockAssembly, _settings);
var result = XmlHelper.CreateXElement(_driver.Run(null, EMPTY_FILTER));
Assert.That(result.Name.LocalName, Is.EqualTo("test-run"));
Assert.That(result.Name.LocalName, Is.EqualTo("test-suite"));
Assert.That(result.GetAttribute("type"), Is.EqualTo("Assembly"));
Assert.That(result.GetAttribute("runstate"), Is.EqualTo("Runnable"));
Assert.That(result.GetAttribute("testcasecount"), Is.EqualTo(MockAssembly.Tests.ToString()));
Assert.That(result.GetAttribute("result"), Is.EqualTo("Failed"));
Assert.That(result.GetAttribute("passed"), Is.EqualTo(MockAssembly.Success.ToString()));
Assert.That(result.GetAttribute("failed"), Is.EqualTo(MockAssembly.ErrorsAndFailures.ToString()));
Assert.That(result.GetAttribute("skipped"), Is.EqualTo(MockAssembly.Skipped.ToString()));
Assert.That(result.GetAttribute("inconclusive"), Is.EqualTo(MockAssembly.Inconclusive.ToString()));
Assert.That(result.Elements("test-suite").Count(), Is.GreaterThan(0), "Explore result should have child tests");
var testSuite = result.Element(XName.Get("test-suite"));
Assert.That(testSuite.GetAttribute("type"), Is.EqualTo("Assembly"));
Assert.That(testSuite.GetAttribute("runstate"), Is.EqualTo("Runnable"));
Assert.That(testSuite.GetAttribute("testcasecount"), Is.EqualTo(MockAssembly.Tests.ToString()));
Assert.That(testSuite.GetAttribute("result"), Is.EqualTo("Failed"));
Assert.That(testSuite.GetAttribute("passed"), Is.EqualTo(MockAssembly.Success.ToString()));
Assert.That(testSuite.GetAttribute("failed"), Is.EqualTo(MockAssembly.ErrorsAndFailures.ToString()));
Assert.That(testSuite.GetAttribute("skipped"), Is.EqualTo(MockAssembly.Skipped.ToString()));
Assert.That(testSuite.GetAttribute("inconclusive"), Is.EqualTo(MockAssembly.Inconclusive.ToString()));
Assert.That(testSuite.Elements("test-suite").Count(), Is.GreaterThan(0), "Explore result should have child tests");
}
[Test]
@ -144,19 +140,5 @@ namespace NUnit.Engine.Tests
Assert.That(ex.Message, Is.EqualTo(LOAD_MESSAGE));
}
#endregion
#region Nested Callback Class
private class CallbackEventHandler
{
public Action<string> Action { get; private set; }
public CallbackEventHandler()
{
Action = s => Result = s;
}
public string Result { get; private set; }
}
#endregion
}
}

Просмотреть файл

@ -40,6 +40,5 @@
"mock-assembly": {
"target": "project"
},
"NUnitLite": "3.4.0"
}
"NUnitLite": "3.5.0" }
}

Просмотреть файл

@ -27,6 +27,6 @@
"NUnit.Portable.Agent": {
"target": "project"
},
"NUnit": "3.4.0"
"NUnit": "3.5.0"
}
}