Skip to content

Commit 41885ae

Browse files
committed
Fix for issue #671, exception stacktrace from OneTimeSetup
1 parent 52d8342 commit 41885ae

File tree

5 files changed

+78
-41
lines changed

5 files changed

+78
-41
lines changed

.runsettings

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<RunSettings>
3-
<RunConfiguration>
4-
<!-- 0 = As many processes as possible, limited by number of cores on machine, 1 = Sequential (1 process), 2-> Given number of processes up to limit by number of cores on machine-->
5-
<MaxCpuCount>0</MaxCpuCount>
6-
7-
</RunConfiguration>
3+
<RunConfiguration>
4+
<!-- 0 = As many processes as possible, limited by number of cores on machine, 1 = Sequential (1 process), 2-> Given number of processes up to limit by number of cores on machine-->
5+
<MaxCpuCount>0</MaxCpuCount>
6+
7+
</RunConfiguration>
88

99
<!--
1010
<TestRunParameters>
@@ -46,9 +46,9 @@
4646

4747
<NUnit>
4848
<Verbosity>5</Verbosity>
49-
<DumpXmlTestResults>true</DumpXmlTestResults>
50-
<DumpXmlTestDiscovery>true</DumpXmlTestDiscovery>
51-
<DiscoveryMethod>Current</DiscoveryMethod>
49+
<DumpXmlTestResults>true</DumpXmlTestResults>
50+
<DumpXmlTestDiscovery>true</DumpXmlTestDiscovery>
51+
<DiscoveryMethod>Current</DiscoveryMethod>
5252
</NUnit>
5353

5454

src/NUnitTestAdapter/AdapterSettings.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public interface IAdapterSettings
111111
int AssemblySelectLimit { get; }
112112

113113
bool UseNUnitFilter { get; }
114+
bool IncludeStackTraceForSuites { get; }
114115

115116

116117
void Load(IDiscoveryContext context);
@@ -236,6 +237,7 @@ public AdapterSettings(ITestLogger logger)
236237
public bool SkipNonTestAssemblies { get; private set; }
237238
public int AssemblySelectLimit { get; private set; }
238239
public bool UseNUnitFilter { get; private set; }
240+
public bool IncludeStackTraceForSuites { get; private set; }
239241

240242
public VsTestCategoryType VsTestCategoryType { get; private set; } = VsTestCategoryType.NUnit;
241243

@@ -322,7 +324,7 @@ public void Load(string settingsXml)
322324
ConsoleOut = GetInnerTextAsInt(nunitNode, nameof(ConsoleOut), 1); // 0 no output to console, 1 : output to console
323325
StopOnError = GetInnerTextAsBool(nunitNode, nameof(StopOnError), false);
324326
UseNUnitFilter = GetInnerTextAsBool(nunitNode, nameof(UseNUnitFilter), true);
325-
327+
IncludeStackTraceForSuites = GetInnerTextAsBool(nunitNode, nameof(IncludeStackTraceForSuites), true);
326328

327329
// Engine settings
328330
DiscoveryMethod = MapEnum(GetInnerText(nunitNode, nameof(DiscoveryMethod), Verbosity > 0), DiscoveryMethod.Current);

src/NUnitTestAdapter/NUnitEngine/NUnitTestEventSuiteFinished.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public interface INUnitTestEventSuiteFinished : INUnitTestEvent
88
bool HasReason { get; }
99
string FailureMessage { get; }
1010
bool HasFailure { get; }
11+
string StackTrace { get; }
1112
}
1213

1314
/// <summary>
@@ -28,14 +29,17 @@ public NUnitTestEventSuiteFinished(XmlNode node) : base(node)
2829
if (failureNode != null)
2930
{
3031
FailureMessage = failureNode.SelectSingleNode("message")?.InnerText;
32+
StackTrace = failureNode.SelectSingleNode("stack-trace")?.InnerText;
3133
}
3234
ReasonMessage = Node.SelectSingleNode("reason/message")?.InnerText;
3335
}
3436

3537
public string ReasonMessage { get; }
3638

3739
public bool HasReason => !string.IsNullOrEmpty(ReasonMessage);
38-
public string FailureMessage { get; }
40+
public string FailureMessage { get; } = "";
41+
42+
public string StackTrace { get; } = "";
3943

4044
public bool HasFailure => !string.IsNullOrEmpty(FailureMessage);
4145
}

src/NUnitTestAdapter/NUnitEventListener.cs

+32-31
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ public class NUnitEventListener :
4747
ITestEventListener, IDisposable // Public for testing
4848
{
4949
private static readonly ICollection<INUnitTestEventTestOutput> EmptyNodes = new List<INUnitTestEventTestOutput>();
50-
private readonly ITestExecutionRecorder _recorder;
51-
private readonly ITestConverterCommon _testConverter;
52-
private readonly IAdapterSettings _settings;
53-
private readonly Dictionary<string, ICollection<INUnitTestEventTestOutput>> _outputNodes = new ();
50+
private readonly ITestExecutionRecorder recorder;
51+
private readonly ITestConverterCommon testConverter;
52+
private readonly IAdapterSettings settings;
53+
private readonly Dictionary<string, ICollection<INUnitTestEventTestOutput>> outputNodes = new ();
5454

5555
#if NET35
5656
public override object InitializeLifetimeService()
@@ -69,9 +69,9 @@ public NUnitEventListener(ITestConverterCommon testConverter, INUnit3TestExecuto
6969
{
7070
this.executor = executor;
7171
dumpXml = executor.Dump;
72-
_settings = executor.Settings;
73-
_recorder = executor.FrameworkHandle;
74-
_testConverter = testConverter;
72+
settings = executor.Settings;
73+
recorder = executor.FrameworkHandle;
74+
this.testConverter = testConverter;
7575
}
7676

7777
#region ITestEventListener
@@ -103,8 +103,8 @@ public void OnTestEvent(string report)
103103
}
104104
catch (Exception ex)
105105
{
106-
_recorder.SendMessage(TestMessageLevel.Warning, $"Error processing {node.Name} event for {node.FullName}");
107-
_recorder.SendMessage(TestMessageLevel.Warning, ex.ToString());
106+
recorder.SendMessage(TestMessageLevel.Warning, $"Error processing {node.Name} event for {node.FullName}");
107+
recorder.SendMessage(TestMessageLevel.Warning, ex.ToString());
108108
}
109109
}
110110

@@ -141,44 +141,44 @@ protected virtual void Dispose(bool disposing)
141141

142142
public void TestStarted(INUnitTestEventStartTest testNode)
143143
{
144-
var ourCase = _testConverter.GetCachedTestCase(testNode.Id);
144+
var ourCase = testConverter.GetCachedTestCase(testNode.Id);
145145

146146
// Simply ignore any TestCase not found in the cache
147147
if (ourCase != null)
148-
_recorder.RecordStart(ourCase);
148+
recorder.RecordStart(ourCase);
149149
}
150150

151151
public void TestFinished(INUnitTestEventTestCase resultNode)
152152
{
153153
var testId = resultNode.Id;
154-
if (_outputNodes.TryGetValue(testId, out var outputNodes))
154+
if (this.outputNodes.TryGetValue(testId, out var outputNodes))
155155
{
156-
_outputNodes.Remove(testId);
156+
this.outputNodes.Remove(testId);
157157
}
158158

159-
var result = _testConverter.GetVsTestResults(resultNode, outputNodes ?? EmptyNodes);
160-
if (_settings.ConsoleOut == 1)
159+
var result = testConverter.GetVsTestResults(resultNode, outputNodes ?? EmptyNodes);
160+
if (settings.ConsoleOut == 1)
161161
{
162162
if (!string.IsNullOrEmpty(result.ConsoleOutput) && result.ConsoleOutput != NL)
163163
{
164164
string msg = result.ConsoleOutput;
165-
if (_settings.UseTestNameInConsoleOutput)
165+
if (settings.UseTestNameInConsoleOutput)
166166
msg = $"{resultNode.Name}: {msg}";
167-
_recorder.SendMessage(TestMessageLevel.Informational, msg);
167+
recorder.SendMessage(TestMessageLevel.Informational, msg);
168168
}
169169
if (!string.IsNullOrEmpty(resultNode.ReasonMessage))
170170
{
171-
_recorder.SendMessage(TestMessageLevel.Informational, $"{resultNode.Name}: {resultNode.ReasonMessage}");
171+
recorder.SendMessage(TestMessageLevel.Informational, $"{resultNode.Name}: {resultNode.ReasonMessage}");
172172
}
173173
}
174174

175-
_recorder.RecordEnd(result.TestCaseResult.TestCase, result.TestCaseResult.Outcome);
175+
recorder.RecordEnd(result.TestCaseResult.TestCase, result.TestCaseResult.Outcome);
176176
foreach (var vsResult in result.TestResults)
177177
{
178-
_recorder.RecordResult(vsResult);
178+
recorder.RecordResult(vsResult);
179179
}
180180

181-
if (result.TestCaseResult.Outcome == TestOutcome.Failed && _settings.StopOnError)
181+
if (result.TestCaseResult.Outcome == TestOutcome.Failed && settings.StopOnError)
182182
{
183183
executor.StopRun();
184184
}
@@ -191,15 +191,16 @@ public void SuiteFinished(INUnitTestEventSuiteFinished resultNode)
191191
var site = resultNode.Site();
192192
if (site != NUnitTestEvent.SiteType.Setup && site != NUnitTestEvent.SiteType.TearDown)
193193
return;
194-
_recorder.SendMessage(TestMessageLevel.Warning, $"{site} failed for test fixture {resultNode.FullName}");
194+
recorder.SendMessage(TestMessageLevel.Warning, $"{site} failed for test fixture {resultNode.FullName}");
195195

196196
if (resultNode.HasFailure)
197-
_recorder.SendMessage(TestMessageLevel.Warning, resultNode.FailureMessage);
198-
199-
// Should not be any stacktrace on Suite-finished
200-
// var stackNode = resultNode.Failure.StackTrace;
201-
// if (!string.IsNullOrEmpty(stackNode))
202-
// _recorder.SendMessage(TestMessageLevel.Warning, stackNode);
197+
{
198+
string msg = resultNode.FailureMessage;
199+
var stackNode = resultNode.StackTrace;
200+
if (!string.IsNullOrEmpty(stackNode) && settings.IncludeStackTraceForSuites)
201+
msg += $"\nStackTrace: {stackNode}";
202+
recorder.SendMessage(TestMessageLevel.Warning, msg);
203+
}
203204
}
204205

205206
private static readonly string NL = Environment.NewLine;
@@ -222,16 +223,16 @@ public void TestOutput(INUnitTestEventTestOutput outputNodeEvent)
222223
string testId = outputNodeEvent.TestId;
223224
if (!string.IsNullOrEmpty(testId))
224225
{
225-
if (!_outputNodes.TryGetValue(testId, out var outputNodes))
226+
if (!this.outputNodes.TryGetValue(testId, out var outputNodes))
226227
{
227228
outputNodes = new List<INUnitTestEventTestOutput>();
228-
_outputNodes.Add(testId, outputNodes);
229+
this.outputNodes.Add(testId, outputNodes);
229230
}
230231

231232
outputNodes.Add(outputNodeEvent);
232233
}
233234

234-
_recorder.SendMessage(TestMessageLevel.Warning, text);
235+
recorder.SendMessage(TestMessageLevel.Warning, text);
235236
}
236237
}
237238
}

src/NUnitTestAdapterTests/NUnitEngineTests/NUnitTestEventsTests.cs

+30
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,36 @@ public void ThatTestEventIsParsedForFinishSuiteWithFailure()
223223
Assert.That(sut.FailureMessage, Is.EqualTo("One or more child tests had errors"));
224224
}
225225

226+
/// <summary>
227+
/// Exception in OneTimeSetUp
228+
/// </summary>
229+
private readonly string testSuiteFinishedWithFailureAndStackTrace = @"<test-suite type='TestFixture' id='0-1000' name='Tests' fullname='Issue671.Tests' classname='Issue671.Tests' runstate='Runnable' testcasecount='2' result='Failed' label='Error' site='SetUp' start-time='2021-05-29T09:34:10.2386869Z' end-time='2021-05-29T09:34:10.2532435Z' duration='0.014557' total='2' passed='0' failed='2' warnings='0' inconclusive='0' skipped='0' asserts='0'>
230+
<failure>
231+
<message><![CDATA[System.Exception : oops Deep Down]]></message>
232+
<stack-trace><![CDATA[ at Issue671.SomeWhereDeepDown.WhatDoWeDoHere() in d:\repos\NUnit\nunit3-vs-adapter.issues\Issue671\UnitTest1.cs:line 44
233+
at Issue671.Tests.OneTimeSetup() in d:\repos\NUnit\nunit3-vs-adapter.issues\Issue671\UnitTest1.cs:line 12]]></stack-trace>
234+
</failure>
235+
<test-case id='0-1001' name='Test1' fullname='Issue671.Tests.Test1' methodname='Test1' classname='Issue671.Tests' runstate='Runnable' seed='1958545482' result='Failed' label='Error' site='Parent' start-time='2021-05-29T09:34:10.2386869Z' end-time='2021-05-29T09:34:10.2510075Z' duration='0.012408' asserts='0'>
236+
<failure>
237+
<message><![CDATA[OneTimeSetUp: System.Exception : oops Deep Down]]></message>
238+
</failure>
239+
</test-case>
240+
<test-case id='0-1002' name='Test2' fullname='Issue671.Tests.Test2' methodname='Test2' classname='Issue671.Tests' runstate='Runnable' seed='711019934' result='Failed' label='Error' site='Parent' start-time='2021-05-29T09:34:10.2386869Z' end-time='2021-05-29T09:34:10.2523634Z' duration='0.013677' asserts='0'>
241+
<failure>
242+
<message><![CDATA[OneTimeSetUp: System.Exception : oops Deep Down]]></message>
243+
</failure>
244+
</test-case>
245+
</test-suite>";
246+
247+
[Test]
248+
public void ThatTestEventIsParsedForFinishSuiteWithExceptionInOneTimeSetUp()
249+
{
250+
var sut = new NUnitTestEventSuiteFinished(testSuiteFinishedWithFailureAndStackTrace);
251+
Assert.That(sut.HasFailure);
252+
Assert.That(sut.FailureMessage.Length, Is.GreaterThan(0));
253+
Assert.That(sut.StackTrace.Length, Is.GreaterThan(0));
254+
}
255+
226256

227257

228258
private readonly string testCaseSucceedsWithOutput = @"<test-case id='0-1074' name='TestSucceeds' fullname='NUnitTestDemo.SimpleTests.TestSucceeds' methodname='TestSucceeds' classname='NUnitTestDemo.SimpleTests' runstate='Runnable' seed='1232497275' result='Passed' start-time='2020-01-24 11:18:32Z' end-time='2020-01-24 11:18:32Z' duration='0.016868' asserts='1' parentId='0-1073'>

0 commit comments

Comments
 (0)