From ed04d979003c4f7d1946de23d280e732903a31b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1sp=C3=A1r=20Nagy?= Date: Fri, 8 Nov 2024 16:30:07 +0100 Subject: [PATCH 1/2] Fix: NUnit projects fail or provide warning as `TearDown : System.InvalidOperationException : Only static OneTimeSetUp and OneTimeTearDown are allowed for InstancePerTestCase mode.` (#320) --- CHANGELOG.md | 4 +++- .../UnitTestProvider/NUnit3TestGeneratorProvider.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db6e9bcc1..8311eca5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ ## Bug fixes: -*Contributors of this release (in alphabetical order):* +* Fix: NUnit projects fail or provide warning as `TearDown : System.InvalidOperationException : Only static OneTimeSetUp and OneTimeTearDown are allowed for InstancePerTestCase mode.` (#320) + +*Contributors of this release (in alphabetical order):* @gasparnagy # v2.2.0 - 2024-11-07 diff --git a/Reqnroll.Generator/UnitTestProvider/NUnit3TestGeneratorProvider.cs b/Reqnroll.Generator/UnitTestProvider/NUnit3TestGeneratorProvider.cs index 34cfd81e0..1d881bd4c 100644 --- a/Reqnroll.Generator/UnitTestProvider/NUnit3TestGeneratorProvider.cs +++ b/Reqnroll.Generator/UnitTestProvider/NUnit3TestGeneratorProvider.cs @@ -57,7 +57,7 @@ public virtual void SetTestClassInitializeMethod(TestClassGenerationContext gene public virtual void SetTestClassCleanupMethod(TestClassGenerationContext generationContext) { - generationContext.TestClassInitializeMethod.Attributes |= MemberAttributes.Static; + generationContext.TestClassCleanupMethod.Attributes |= MemberAttributes.Static; CodeDomHelper.AddAttribute(generationContext.TestClassCleanupMethod, TESTFIXTURETEARDOWN_ATTR_NUNIT3); } From bea5be10a4a47da6d4373333b6bd5ed72567b3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1sp=C3=A1r=20Nagy?= Date: Fri, 8 Nov 2024 17:01:35 +0100 Subject: [PATCH 2/2] Add tests --- .../Generation/GenerationTestBase.cs | 2 ++ .../Generation/NUnitGenerationTest.cs | 14 ++++++++++ Tests/Reqnroll.SystemTests/SystemTestBase.cs | 5 ++++ .../Extensions/UnitTestProviderExtensions.cs | 4 ++- .../ProjectBuilder.cs | 26 ++++++++++++++++-- .../TRXParser.cs | 27 +++++++++++++------ .../TestExecutionResult.cs | 2 ++ .../UnitTestProvider.cs | 1 + 8 files changed, 70 insertions(+), 11 deletions(-) diff --git a/Tests/Reqnroll.SystemTests/Generation/GenerationTestBase.cs b/Tests/Reqnroll.SystemTests/Generation/GenerationTestBase.cs index 1401a38e5..351b68c82 100644 --- a/Tests/Reqnroll.SystemTests/Generation/GenerationTestBase.cs +++ b/Tests/Reqnroll.SystemTests/Generation/GenerationTestBase.cs @@ -19,6 +19,8 @@ public void GeneratorAllIn_sample_can_be_handled() ExecuteTests(); ShouldAllScenariosPass(); + + ShouldFinishWithoutTestExecutionWarnings(); } [TestMethod] diff --git a/Tests/Reqnroll.SystemTests/Generation/NUnitGenerationTest.cs b/Tests/Reqnroll.SystemTests/Generation/NUnitGenerationTest.cs index f5f8238ef..444ff79c1 100644 --- a/Tests/Reqnroll.SystemTests/Generation/NUnitGenerationTest.cs +++ b/Tests/Reqnroll.SystemTests/Generation/NUnitGenerationTest.cs @@ -18,6 +18,20 @@ protected override void TestInitialize() _testRunConfiguration.UnitTestProvider = UnitTestProvider.NUnit3; } + [TestMethod] + public void GeneratorAllIn_sample_can_be_handled_by_NUnit4() + { + _testRunConfiguration.UnitTestProvider = UnitTestProvider.NUnit4; + + PrepareGeneratorAllInSamples(); + + ExecuteTests(); + + ShouldAllScenariosPass(); + + ShouldFinishWithoutTestExecutionWarnings(); + } + protected override void AssertIgnoredScenarioOutlineExampleHandled() { _vsTestExecutionDriver.LastTestExecutionResult.LeafTestResults diff --git a/Tests/Reqnroll.SystemTests/SystemTestBase.cs b/Tests/Reqnroll.SystemTests/SystemTestBase.cs index c20658040..29031ce12 100644 --- a/Tests/Reqnroll.SystemTests/SystemTestBase.cs +++ b/Tests/Reqnroll.SystemTests/SystemTestBase.cs @@ -226,6 +226,11 @@ protected void ShouldAllScenariosPass(int? expectedNrOfTestsSpec = null) _vsTestExecutionDriver.LastTestExecutionResult.Succeeded.Should().Be(expectedNrOfTests, "all tests should pass"); } + protected void ShouldFinishWithoutTestExecutionWarnings() + { + _vsTestExecutionDriver.LastTestExecutionResult.Warnings.Should().BeEmpty(); + } + protected int ConfirmAllTestsRan(int? expectedNrOfTestsSpec) { if (expectedNrOfTestsSpec == null && _preparedTests == 0) diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Extensions/UnitTestProviderExtensions.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Extensions/UnitTestProviderExtensions.cs index 671bd5ca9..e983d3b2c 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Extensions/UnitTestProviderExtensions.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Extensions/UnitTestProviderExtensions.cs @@ -10,7 +10,9 @@ public static string ToName(this UnitTestProvider unitTestProvider) { case UnitTestProvider.MSTest: return "MSTest"; case UnitTestProvider.NUnit2: return "NUnit2"; - case UnitTestProvider.NUnit3: return "NUnit"; + case UnitTestProvider.NUnit3: + case UnitTestProvider.NUnit4: + return "NUnit"; case UnitTestProvider.xUnit: return "XUnit"; default: throw new ArgumentOutOfRangeException(nameof(unitTestProvider), unitTestProvider, "value is not known"); } diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/ProjectBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/ProjectBuilder.cs index 1eb012049..92f275c78 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/ProjectBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/ProjectBuilder.cs @@ -15,6 +15,10 @@ public class ProjectBuilder public const string NUnit3PackageVersion = "3.13.1"; public const string NUnit3TestAdapterPackageName = "NUnit3TestAdapter"; public const string NUnit3TestAdapterPackageVersion = "3.17.0"; + public const string NUnit4PackageName = "NUnit"; + public const string NUnit4PackageVersion = "4.2.2"; + public const string NUnit4TestAdapterPackageName = "NUnit3TestAdapter"; + public const string NUnit4TestAdapterPackageVersion = "4.6.0"; private const string XUnitPackageVersion = "2.4.2"; private const string MSTestPackageVersion = "2.2.8"; private const string InternalJsonPackageName = "SpecFlow.Internal.Json"; @@ -253,7 +257,10 @@ private void EnsureProjectExists() ConfigureXUnit(); break; case UnitTestProvider.NUnit3: - ConfigureNUnit(); + ConfigureNUnit3(); + break; + case UnitTestProvider.NUnit4: + ConfigureNUnit4(); break; default: throw new InvalidOperationException(@"Invalid unit test provider."); @@ -263,7 +270,7 @@ private void EnsureProjectExists() AddAdditionalStuff(); } - private void ConfigureNUnit() + private void ConfigureNUnit3() { _project.AddNuGetPackage(NUnit3PackageName, NUnit3PackageVersion); _project.AddNuGetPackage(NUnit3TestAdapterPackageName, NUnit3TestAdapterPackageVersion); @@ -277,6 +284,20 @@ private void ConfigureNUnit() } } + private void ConfigureNUnit4() + { + _project.AddNuGetPackage(NUnit4PackageName, NUnit4PackageVersion); + _project.AddNuGetPackage(NUnit4TestAdapterPackageName, NUnit4TestAdapterPackageVersion); + + + if (IsReqnrollFeatureProject) + { + _project.AddNuGetPackage("Reqnroll.NUnit", _currentVersionDriver.ReqnrollNuGetVersion, + new NuGetPackageAssembly(GetReqnrollPublicAssemblyName("Reqnroll.NUnit.ReqnrollPlugin.dll"), "net462\\Reqnroll.NUnit.ReqnrollPlugin.dll")); + Configuration.Plugins.Add(new ReqnrollPlugin("Reqnroll.NUnit", ReqnrollPluginType.Runtime)); + } + } + private void ConfigureXUnit() { if (_project.ProjectFormat == ProjectFormat.New) @@ -348,6 +369,7 @@ private void AddUnitTestProviderSpecificConfig() _project.AddFile(new ProjectFile("XUnitConfiguration.cs", "Compile", "using Xunit; [assembly: CollectionBehavior(CollectionBehavior.CollectionPerClass, MaxParallelThreads = 4)]")); break; case UnitTestProvider.NUnit3 when _parallelTestExecution: + case UnitTestProvider.NUnit4 when _parallelTestExecution: _project.AddFile(new ProjectFile("NUnitConfiguration.cs", "Compile", "[assembly: NUnit.Framework.Parallelizable(NUnit.Framework.ParallelScope.All)]")); break; case UnitTestProvider.MSTest when _parallelTestExecution: diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TRXParser.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TRXParser.cs index 7e7fd7c13..ac78c19e8 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TRXParser.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TRXParser.cs @@ -47,14 +47,16 @@ private TestExecutionResult CalculateTestExecutionResultFromTrx(XDocument trx, T private TestExecutionResult GetCommonTestExecutionResult(XDocument trx, string output, IEnumerable reportFiles, string logFileContent) { var testRunElement = trx.Descendants(_testRunElementName).Single(); - var summaryElement = testRunElement.Element(_xmlns + "ResultSummary")?.Element(_xmlns + "Counters") - ?? throw new InvalidOperationException("Invalid document; result summary counters element not found."); + var summaryElement = testRunElement.Element(_xmlns + "ResultSummary") + ?? throw new InvalidOperationException("Invalid document; result summary element not found."); ; + var summaryCountersElement = summaryElement?.Element(_xmlns + "Counters") + ?? throw new InvalidOperationException("Invalid document; result summary counters element not found."); - var totalAttribute = summaryElement.Attribute("total"); - var executedAttribute = summaryElement.Attribute("executed"); - var passedAttribute = summaryElement.Attribute("passed"); - var failedAttribute = summaryElement.Attribute("failed"); - var inconclusiveAttribute = summaryElement.Attribute("inconclusive"); + var totalAttribute = summaryCountersElement.Attribute("total"); + var executedAttribute = summaryCountersElement.Attribute("executed"); + var passedAttribute = summaryCountersElement.Attribute("passed"); + var failedAttribute = summaryCountersElement.Attribute("failed"); + var inconclusiveAttribute = summaryCountersElement.Attribute("inconclusive"); int.TryParse(totalAttribute?.Value, out int total); int.TryParse(executedAttribute?.Value, out int executed); @@ -62,6 +64,12 @@ private TestExecutionResult GetCommonTestExecutionResult(XDocument trx, string o int.TryParse(failedAttribute?.Value, out int failed); int.TryParse(inconclusiveAttribute?.Value, out int inconclusive); + var runInfos = summaryElement.Element(_xmlns + "RunInfos")?.Elements(_xmlns + "RunInfo") ?? Enumerable.Empty(); + var warnings = runInfos + .Where(ri => "Warning".Equals(ri.Attribute("outcome")?.Value, StringComparison.InvariantCultureIgnoreCase)) + .Select(ri => ri.Element(_xmlns + "Text")?.Value ?? "[no warning text]") + .ToArray(); + var testResults = GetTestResults(testRunElement, _xmlns); var leafTestResults = testResults.Where(tr => tr.InnerResults.Count == 0) @@ -84,6 +92,7 @@ private TestExecutionResult GetCommonTestExecutionResult(XDocument trx, string o Succeeded = passed, Failed = failed, Pending = inconclusive, + Warnings = warnings }; } @@ -93,7 +102,9 @@ private TestExecutionResult CalculateUnitTestProviderSpecificTestExecutionResult { case UnitTestProvider.xUnit: return CalculateXUnitTestExecutionResult(testExecutionResult, trx); case UnitTestProvider.MSTest: return CalculateMsTestTestExecutionResult(testExecutionResult); - case UnitTestProvider.NUnit3: return CalculateNUnitTestExecutionResult(testExecutionResult); + case UnitTestProvider.NUnit3: + case UnitTestProvider.NUnit4: + return CalculateNUnitTestExecutionResult(testExecutionResult); default: throw new NotSupportedException($"The specified unit test provider is not supported: {testRunConfiguration.UnitTestProvider}"); } } diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TestExecutionResult.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TestExecutionResult.cs index 1c9680b29..7f89932d7 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TestExecutionResult.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/TestExecutionResult.cs @@ -25,6 +25,8 @@ public class TestExecutionResult public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } + + public string[] Warnings { get; set; } } public class TestResult diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/UnitTestProvider.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/UnitTestProvider.cs index 3211585c4..d76b3d6e9 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/UnitTestProvider.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/UnitTestProvider.cs @@ -4,6 +4,7 @@ public enum UnitTestProvider { MSTest, xUnit, + NUnit4, NUnit3, NUnit2 } \ No newline at end of file