diff --git a/src/NUnitTestAdapter/AdapterSettings.cs b/src/NUnitTestAdapter/AdapterSettings.cs
index 71755188..099e820f 100644
--- a/src/NUnitTestAdapter/AdapterSettings.cs
+++ b/src/NUnitTestAdapter/AdapterSettings.cs
@@ -50,15 +50,16 @@ public interface IAdapterSettings
int? RandomSeed { get; }
bool RandomSeedSpecified { get; }
bool InProcDataCollectorsAvailable { get; }
+ bool CollectDataForEachTestSeparately { get; }
bool SynchronousEvents { get; }
- string DomainUsage { get; }
- bool DumpXmlTestDiscovery { get; }
- bool DumpXmlTestResults { get; }
+ string DomainUsage { get; }
+ bool DumpXmlTestDiscovery { get; }
+ bool DumpXmlTestResults { get; }
///
/// Syntax documentation
///
- string DefaultTestNamePattern { get; }
+ string DefaultTestNamePattern { get; }
void Load(IDiscoveryContext context);
void Load(string settingsXml);
@@ -143,6 +144,8 @@ public AdapterSettings(TestLogger logger)
public int? RandomSeed { get; private set; }
public bool RandomSeedSpecified { get; private set; }
+ public bool CollectDataForEachTestSeparately { get; private set; }
+
public bool InProcDataCollectorsAvailable { get; private set; }
public bool SynchronousEvents { get; private set; }
@@ -195,6 +198,7 @@ public void Load(string settingsXml)
DisableAppDomain = GetInnerTextAsBool(runConfiguration, nameof(DisableAppDomain), false);
DisableParallelization = GetInnerTextAsBool(runConfiguration, nameof(DisableParallelization), false);
DesignMode = GetInnerTextAsBool(runConfiguration, nameof(DesignMode), false);
+ CollectDataForEachTestSeparately = GetInnerTextAsBool(runConfiguration, nameof(CollectDataForEachTestSeparately), false);
TestProperties = new Dictionary();
foreach (XmlNode node in doc.SelectNodes("RunSettings/TestRunParameters/Parameter"))
@@ -205,7 +209,7 @@ public void Load(string settingsXml)
TestProperties.Add(key, value);
}
- // NUnit settings
+ // NUnit settings
InternalTraceLevel = GetInnerTextWithLog(nunitNode, nameof(InternalTraceLevel), "Off", "Error", "Warning", "Info", "Verbose", "Debug");
WorkDirectory = GetInnerTextWithLog(nunitNode, nameof(WorkDirectory));
DefaultTimeout = GetInnerTextAsInt(nunitNode, nameof(DefaultTimeout), 0);
@@ -220,8 +224,8 @@ public void Load(string settingsXml)
RandomSeed = new Random().Next();
DefaultTestNamePattern = GetInnerTextWithLog(nunitNode, nameof(DefaultTestNamePattern));
- DumpXmlTestDiscovery = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestDiscovery),false);
- DumpXmlTestResults= GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestResults), false);
+ DumpXmlTestDiscovery = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestDiscovery), false);
+ DumpXmlTestResults = GetInnerTextAsBool(nunitNode, nameof(DumpXmlTestResults), false);
@@ -241,22 +245,31 @@ public void Load(string settingsXml)
Verbosity = 1;
#endif
- // If any in proc data collector will be instantiated by the TestPlatform run tests sequentially.
var inProcDataCollectorNode = doc.SelectSingleNode("RunSettings/InProcDataCollectionRunSettings/InProcDataCollectors");
InProcDataCollectorsAvailable = inProcDataCollectorNode != null && inProcDataCollectorNode.SelectNodes("InProcDataCollector").Count > 0;
- if (InProcDataCollectorsAvailable)
+
+ // Older versions of VS do not pass the CollectDataForEachTestSeparately configuration together with the LiveUnitTesting collector.
+ // However, the adapter is expected to run in CollectDataForEachTestSeparately mode.
+ // As a result for backwards compatibility reasons enable CollectDataForEachTestSeparately mode whenever LiveUnitTesting collector is being used.
+ var hasLiveUnitTestingDataCollector = inProcDataCollectorNode?.SelectSingleNode("InProcDataCollector[@uri='InProcDataCollector://Microsoft/LiveUnitTesting/1.0']") != null;
+
+ // TestPlatform can opt-in to run tests one at a time so that the InProcDataCollectors can collect the data for each one of them separately.
+ // In that case, we need to ensure that tests do not run in parallel and the test started/test ended events are sent synchronously.
+ if (CollectDataForEachTestSeparately || hasLiveUnitTestingDataCollector)
{
NumberOfTestWorkers = 0;
- DomainUsage = "None";
SynchronousEvents = true;
if (Verbosity >= 4)
{
- _logger.Info($"InProcDataCollectors are available: turning off Parallel, DomainUsage=None, SynchronousEvents=true");
+ if (!InProcDataCollectorsAvailable)
+ {
+ _logger.Info("CollectDataForEachTestSeparately is set, which is used to make InProcDataCollectors collect data for each test separately. No InProcDataCollectors can be found, thus the tests will run slower unnecessarily.");
+ }
}
}
// If DisableAppDomain settings is passed from the testplatform, set the DomainUsage to None.
- if(DisableAppDomain)
+ if (DisableAppDomain)
{
DomainUsage = "None";
}
@@ -301,13 +314,13 @@ public void RestoreRandomSeed(string dirname)
private void UpdateNumberOfTestWorkers()
{
// Overriding the NumberOfTestWorkers if DisableParallelization is true.
- if(DisableParallelization && NumberOfTestWorkers < 0)
+ if (DisableParallelization && NumberOfTestWorkers < 0)
{
NumberOfTestWorkers = 0;
}
- else if(DisableParallelization && NumberOfTestWorkers > 0)
+ else if (DisableParallelization && NumberOfTestWorkers > 0)
{
- if(_logger.Verbosity > 0)
+ if (_logger.Verbosity > 0)
{
_logger.Warning(string.Format("DisableParallelization:{0} & NumberOfTestWorkers:{1} are conflicting settings, hence not running in parallel", DisableParallelization, NumberOfTestWorkers));
}
@@ -339,17 +352,17 @@ private string GetInnerText(XmlNode startNode, string xpath, bool log, params st
"Invalid value {0} passed for element {1}.", val, xpath));
}
-
+
}
if (log)
- Log(xpath,val);
+ Log(xpath, val);
return val;
}
private int GetInnerTextAsInt(XmlNode startNode, string xpath, int defaultValue)
{
- var temp = GetInnerTextAsNullableInt(startNode, xpath,false);
+ var temp = GetInnerTextAsNullableInt(startNode, xpath, false);
var res = defaultValue;
if (temp != null)
res = temp.Value;
@@ -357,24 +370,24 @@ private int GetInnerTextAsInt(XmlNode startNode, string xpath, int defaultValue)
return res;
}
- private int? GetInnerTextAsNullableInt(XmlNode startNode, string xpath,bool log=true)
+ private int? GetInnerTextAsNullableInt(XmlNode startNode, string xpath, bool log = true)
{
- string temp = GetInnerText(startNode, xpath,log);
+ string temp = GetInnerText(startNode, xpath, log);
int? res = null;
if (!string.IsNullOrEmpty(temp))
res = int.Parse(temp);
if (log)
- Log(xpath,res);
+ Log(xpath, res);
return res;
}
private bool GetInnerTextAsBool(XmlNode startNode, string xpath, bool defaultValue)
{
- string temp = GetInnerText(startNode, xpath,false);
+ string temp = GetInnerText(startNode, xpath, false);
bool res = defaultValue;
if (!string.IsNullOrEmpty(temp))
res = bool.Parse(temp);
- Log(xpath,res);
+ Log(xpath, res);
return res;
}
diff --git a/src/NUnitTestAdapterTests/AdapterSettingsTests.cs b/src/NUnitTestAdapterTests/AdapterSettingsTests.cs
index 6ba8821b..efd8aeb9 100644
--- a/src/NUnitTestAdapterTests/AdapterSettingsTests.cs
+++ b/src/NUnitTestAdapterTests/AdapterSettingsTests.cs
@@ -242,6 +242,27 @@ public void DefaultTestNamePattern()
Assert.That(_settings.DefaultTestNamePattern,Is.EqualTo("{m}{a:1000}"));
}
+ [Test]
+ public void CollectDataForEachTestSeparately()
+ {
+ _settings.Load(@"
+
+
+ true
+
+
+
+
+
+
+");
+
+ Assert.Null(_settings.DomainUsage);
+ Assert.True(_settings.SynchronousEvents);
+ Assert.That(_settings.NumberOfTestWorkers, Is.Zero);
+ Assert.True(_settings.InProcDataCollectorsAvailable);
+ }
+
[Test]
public void InProcDataCollector()
{
@@ -254,7 +275,25 @@ public void InProcDataCollector()
");
- Assert.That(_settings.DomainUsage, Is.EqualTo("None"));
+ Assert.Null(_settings.DomainUsage);
+ Assert.False(_settings.SynchronousEvents);
+ Assert.That(_settings.NumberOfTestWorkers, Is.EqualTo(-1));
+ Assert.True(_settings.InProcDataCollectorsAvailable);
+ }
+
+ [Test]
+ public void LiveUnitTestingDataCollector()
+ {
+ _settings.Load(@"
+
+
+
+
+
+
+");
+
+ Assert.Null(_settings.DomainUsage);
Assert.True(_settings.SynchronousEvents);
Assert.That(_settings.NumberOfTestWorkers, Is.Zero);
Assert.True(_settings.InProcDataCollectorsAvailable);