Skip to content

Commit

Permalink
Fleshing out Generation System Tests (2) (#99)
Browse files Browse the repository at this point in the history
* Commit to flesh out Generation System Test.

* Added test to verify that async step bindings are executed in the order specified in the Scenario.

* Tests that verify that Before/After Hooks are run.

* cleanup; promoted some code from GenerationTestBAse to SystemTestBase.

* Adjusted the expectations of the Undefined Step test to account for different handling by MSTest.
Adjusted Ignored test to disable row tests; this provides for consistent handling by all three test frameworks.

* fix build

* code cleanup

* refactor common scenarios

* Improve hook / step assertions

* Merge outcome related tests

* Fixes Adding @ignore to an Examples block generates invalid code for NUnit v3+ issue (#103)

* Add fix to CHANGELOG

* cleanup

* Test scenario outlines (nr of examples, params are available in ScenarioContext, examples tags)

* Add portability tests for before/after test run hooks (.NET Framework version of Reqnroll is subscribed to assembly unload)

---------

Co-authored-by: Chris Rudolphi <[email protected]>
  • Loading branch information
gasparnagy and clrudolphi authored Apr 17, 2024
1 parent 791b0c5 commit 77bea54
Show file tree
Hide file tree
Showing 37 changed files with 644 additions and 137 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Support for PriorityAttribute in MsTest adapter
* Support for Scenario Outline / DataRowAttribute in MsTest adapter
* Fix for #81 in which Cucumber Expressions fail when two enums with the same short name (differing namespaces) are used as parameters
* Fix: Adding @ignore to an Examples block generates invalid code for NUnit v3+ (#103)

# v1.0.1 - 2024-02-16

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public void SetRow(TestClassGenerationContext generationContext, CodeMemberMetho
}

if (isIgnored)
args.Add(new CodeAttributeArgument("Ignored", new CodePrimitiveExpression(true)));
args.Add(new CodeAttributeArgument("IgnoreReason", new CodePrimitiveExpression("Ignored by @ignore tag")));

CodeDomHelper.AddAttribute(testMethod, ROW_ATTR, args.ToArray());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Reqnroll.TestProjectGenerator.ConfigurationModel;
using Reqnroll.TestProjectGenerator.Data;
using Reqnroll.TestProjectGenerator.Factories.ConfigurationGenerator;
using Reqnroll.TestProjectGenerator.NewApi._1_Memory;
using Xunit;

namespace Reqnroll.TestProjectGenerator.Tests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using FluentAssertions;
using Reqnroll.TestProjectGenerator.NewApi._1_Memory;
using Xunit;

namespace Reqnroll.TestProjectGenerator.Tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Reqnroll.TestProjectGenerator.ConfigurationModel;
using Reqnroll.TestProjectGenerator.Data;
using Reqnroll.TestProjectGenerator.Factories.ConfigurationGenerator;
using Reqnroll.TestProjectGenerator.NewApi._1_Memory;
using Xunit;

namespace Reqnroll.TestProjectGenerator.Tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Globalization;
using Reqnroll.TestProjectGenerator.Data;
using Reqnroll.TestProjectGenerator.NewApi._1_Memory;

namespace Reqnroll.TestProjectGenerator.ConfigurationModel
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Reqnroll.TestProjectGenerator.NewApi._1_Memory
namespace Reqnroll.TestProjectGenerator.Data
{
public class AppConfigSection
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
namespace Reqnroll.TestProjectGenerator.Data
{
[DebuggerDisplay("{" + nameof(Path) + ("} [{" + nameof(BuildAction) + "}]"))]
public class ProjectFile :SolutionFile //FeatureFiles, Code, App.Config, NuGet.Config, packages.config,
public class ProjectFile: SolutionFile //FeatureFiles, Code, App.Config, NuGet.Config, packages.config,
{
public ProjectFile(string path, string buildAction, string content, CopyToOutputDirectory copyToOutputDirectory = CopyToOutputDirectory.DoNotCopy) :
this(path, buildAction, content, copyToOutputDirectory, new Dictionary<string, string>())
{

}

public ProjectFile(string path, string buildAction, string content, CopyToOutputDirectory copyToOutputDirectory, IReadOnlyDictionary<string, string> additionalMsBuildProperties) : base(path, content)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
using System;

namespace Reqnroll.TestProjectGenerator.Data
{
public class SolutionFile
public class SolutionFile(string path, string content)
{
public SolutionFile(string path, string content)
private bool _isFrozen = false;

public string Path { get; } = path; //relative from project
public string Content { get; private set; } = content;

internal void Freeze()
{
Path = path;
Content = content;
_isFrozen = true;
}

public string Path { get; } //relative from project
public string Content { get; }
public void Append(string addedContent)
{
if (_isFrozen)
{
throw new InvalidOperationException("Cannot append to frozen file");
}

if (!Content.EndsWith(Environment.NewLine))
Content += Environment.NewLine;

Content += addedContent;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,8 @@

namespace Reqnroll.TestProjectGenerator.Driver
{
public class HooksDriver
public class BindingsDriver(TestProjectFolders _testProjectFolders)
{
private readonly TestProjectFolders _testProjectFolders;

public HooksDriver(TestProjectFolders testProjectFolders)
{
_testProjectFolders = testProjectFolders;
}

public void CheckIsHookExecuted(string methodName, int expectedTimesExecuted)
{
int hookExecutionCount = GetHookExecutionCount(methodName);
Expand All @@ -27,27 +20,28 @@ public int GetHookExecutionCount(string methodName)
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();

string pathToHookLogFile = Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log");
if (!File.Exists(pathToHookLogFile))
if (!File.Exists(_testProjectFolders.LogFilePath))
{
return 0;
}

string content = File.ReadAllText(pathToHookLogFile);
string content = File.ReadAllText(_testProjectFolders.LogFilePath);
content.Should().NotBeNull();

var regex = new Regex($@"-> hook: {methodName}");

return regex.Matches(content).Count;
}

private string GetLogFileLockPath() => _testProjectFolders.LogFilePath + ".lock";

public void AcquireHookLock()
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();

var pathToHookLogFile = Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log.lock");
var pathToHookLogFile = GetLogFileLockPath();

Directory.CreateDirectory(Path.GetDirectoryName(pathToHookLogFile));
Directory.CreateDirectory(Path.GetDirectoryName(pathToHookLogFile)!);
using (File.Open(pathToHookLogFile, FileMode.CreateNew))
{
}
Expand All @@ -56,10 +50,7 @@ public void AcquireHookLock()
public void ReleaseHookLock()
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();

var pathToHookLogFile = Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log.lock");

File.Delete(pathToHookLogFile);
File.Delete(GetLogFileLockPath());
}

public async Task WaitForIsWaitingForHookLockAsync(string methodName)
Expand All @@ -81,42 +72,73 @@ private bool CheckIsWaitingForHookLock(string methodName)
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();

var pathToHookLogFile = Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log");

if (!File.Exists(pathToHookLogFile))
if (!File.Exists(_testProjectFolders.LogFilePath))
{
return false;
}

var content = File.ReadAllText(pathToHookLogFile);
var content = File.ReadAllText(_testProjectFolders.LogFilePath);
content.Should().NotBeNull();

var regex = new Regex($@"-> waiting for hook lock: {methodName}");

return regex.Matches(content).Count == 1;
}

public IEnumerable<string> GetActualLogLines(string category)
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();

var lines = File.ReadAllLines(_testProjectFolders.LogFilePath);
return lines.Where(l => l.StartsWith($"-> {category}:"));
}

public void CheckIsNotHookExecuted(string methodName, int timesExecuted)
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();

var pathToHookLogFile = Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log");
var content = File.ReadAllText(pathToHookLogFile);
var content = File.ReadAllText(_testProjectFolders.LogFilePath);
content.Should().NotBeNull();

var regex = new Regex($@"-> hook: {methodName}");

regex.Matches(content).Count.Should().NotBe(timesExecuted);
}

public void CheckIsHookExecutedInOrder(IEnumerable<string> methodNames)
private IEnumerable<string> GetActualHookLines() => GetActualLogLines("hook");

public void AssertHooksExecutedInOrder(params string[] methodNames)
{
_testProjectFolders.PathToSolutionDirectory.Should().NotBeNullOrWhiteSpace();
var hookLines = GetActualHookLines();

var pathToHookLogFile = Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log");
var lines = File.ReadAllLines(pathToHookLogFile);
var methodNameLines = methodNames.Select(m => $"-> hook: {m}");
lines.Should().ContainInOrder(methodNameLines);
hookLines.Should().ContainInOrder(methodNameLines);
}

public void AssertExecutedHooksEqual(params string[] methodNames)
{
var hookLines = GetActualHookLines();

var methodNameLines = methodNames.Select(m => $"-> hook: {m}");
hookLines.Should().Equal(methodNameLines);
}

private IEnumerable<string> GetActualStepLines() => GetActualLogLines("step");

public void AssertStepsExecutedInOrder(params string[] methodNames)
{
var stepLines = GetActualStepLines();

var methodNameLines = methodNames.Select(m => $"-> step: {m}");
stepLines.Should().ContainInOrder(methodNameLines);
}

public void AssertExecutedStepsEqual(params string[] methodNames)
{
var stepLines = GetActualStepLines();

var methodNameLines = methodNames.Select(m => $"-> step: {m}");
stepLines.Should().Equal(methodNameLines);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

namespace Reqnroll.TestProjectGenerator.Driver
{
public class ConfigurationDriver
public class ConfigurationFileDriver
{
private readonly SolutionDriver _solutionDriver;

public ConfigurationDriver(SolutionDriver solutionDriver)
public ConfigurationFileDriver(SolutionDriver solutionDriver)
{
_solutionDriver = solutionDriver;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ namespace Reqnroll.TestProjectGenerator.Driver
public class JsonConfigurationLoaderDriver
{
private readonly ProjectsDriver _projectsDriver;
private readonly ConfigurationDriver _configurationDriver;
private readonly ConfigurationFileDriver _configurationFileDriver;

public JsonConfigurationLoaderDriver(ProjectsDriver projectsDriver, ConfigurationDriver configurationDriver)
public JsonConfigurationLoaderDriver(ProjectsDriver projectsDriver, ConfigurationFileDriver configurationFileDriver)
{
_projectsDriver = projectsDriver;
_configurationDriver = configurationDriver;
_configurationFileDriver = configurationFileDriver;
}

public void AddReqnrollJson(string reqnrollJson)
{
_configurationDriver.SetConfigurationFormat(ConfigurationFormat.None);
_configurationFileDriver.SetConfigurationFormat(ConfigurationFormat.None);
_projectsDriver.AddFile("reqnroll.json", reqnrollJson);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class ProjectsDriver
private readonly SolutionDriver _solutionDriver;
private readonly ProjectBuilderFactory _projectBuilderFactory;
private readonly TestProjectFolders _testProjectFolders;
public ProjectFile LastFeatureFile { get; private set; }

public ProjectsDriver(SolutionDriver solutionDriver, ProjectBuilderFactory projectBuilderFactory, TestProjectFolders testProjectFolders)
{
Expand Down Expand Up @@ -59,9 +60,9 @@ public void AddHookBinding(string eventType, string name, string hookTypeAttribu
AddHookBinding(_solutionDriver.DefaultProject, eventType, name, code, order, hookTypeAttributeTags, methodScopeAttributeTags, classScopeAttributeTags);
}

public void AddHookBinding(string eventType, string name, string code = "", int? order = null, IList<string> hookTypeAttributeTags = null, IList<string> methodScopeAttributeTags = null, IList<string> classScopeAttributeTags = null)
public void AddHookBinding(string eventType, string name = null, string code = "", int? order = null, IList<string> hookTypeAttributeTags = null, IList<string> methodScopeAttributeTags = null, IList<string> classScopeAttributeTags = null)
{
AddHookBinding(_solutionDriver.DefaultProject, eventType, name, code, order, hookTypeAttributeTags, methodScopeAttributeTags, classScopeAttributeTags);
AddHookBinding(_solutionDriver.DefaultProject, eventType, name ?? eventType, code, order, hookTypeAttributeTags, methodScopeAttributeTags, classScopeAttributeTags);
}

private void AddHookBinding(ProjectBuilder project, string eventType, string name, string code = "", int? order = null, IList<string> hookTypeAttributeTags = null, IList<string> methodScopeAttributeTags = null, IList<string> classScopeAttributeTags = null)
Expand All @@ -81,27 +82,34 @@ private void AddAsyncHookBindingIncludingLocking(ProjectBuilder project, string

public void AddFeatureFile(string featureFileContent)
{
_solutionDriver.DefaultProject.AddFeatureFile(featureFileContent);
LastFeatureFile = _solutionDriver.DefaultProject.AddFeatureFile(featureFileContent);
}

public void AddScenario(string scenarioContent)
{
AddFeatureFile(
$$"""
Feature: Sample Feature
{{scenarioContent}}
""");
if (LastFeatureFile != null)
{
LastFeatureFile.Append(scenarioContent);
}
else
{
AddFeatureFile(
$$"""
Feature: Sample Feature
{{scenarioContent}}
""");
}
}

public void AddStepBinding(string attributeName, string regex, string csharpcode, string vbnetcode)
public void AddStepBinding(string attributeName, string regex, string csharpcode, string vbnetcode = null)
{
_solutionDriver.DefaultProject.AddStepBinding(attributeName, regex, csharpcode, vbnetcode);
}

public void AddLoggingStepBinding(string attributeName, string methodName, string regex)
{
_solutionDriver.DefaultProject.AddLoggingStepBinding(attributeName, methodName, Path.Combine(_testProjectFolders.PathToSolutionDirectory, "steps.log"), regex);
_solutionDriver.DefaultProject.AddLoggingStepBinding(attributeName, methodName, regex);
}

public void AddStepBinding(string projectName, string bindingCode) => AddStepBinding(_solutionDriver.Projects[projectName], bindingCode);
Expand Down Expand Up @@ -157,7 +165,7 @@ public void AddNuGetPackage(string nugetPackage, string nugetVersion)
_solutionDriver.DefaultProject.AddNuGetPackage(nugetPackage, nugetVersion);
}

public void AddFailingStepBinding(string scenarioBlock, string stepRegex)
public void AddFailingStepBinding(string scenarioBlock = "StepDefinition", string stepRegex = ".*")
{
AddStepBinding(scenarioBlock, stepRegex, @"throw new System.Exception(""simulated failure"");", @"Throw New System.Exception(""simulated failure"")");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ public class TestSuiteSetupDriver
private readonly ProjectsDriver _projectsDriver;
private readonly TestSuiteInitializationDriver _testSuiteInitializationDriver;
private readonly JsonConfigurationLoaderDriver _jsonConfigurationLoaderDriver;
private readonly ConfigurationDriver _configurationDriver;
private readonly ConfigurationFileDriver _configurationFileDriver;
private bool _isProjectCreated;

public TestSuiteSetupDriver(ProjectsDriver projectsDriver, TestSuiteInitializationDriver testSuiteInitializationDriver, JsonConfigurationLoaderDriver jsonConfigurationLoaderDriver,
ConfigurationDriver configurationDriver)
ConfigurationFileDriver configurationFileDriver)
{
_projectsDriver = projectsDriver;
_testSuiteInitializationDriver = testSuiteInitializationDriver;
_jsonConfigurationLoaderDriver = jsonConfigurationLoaderDriver;
_configurationDriver = configurationDriver;
_configurationFileDriver = configurationFileDriver;
}

public void AddGenericWhenStepBinding()
Expand Down Expand Up @@ -136,7 +136,7 @@ public void AddScenarioWithGivenStep(string step, string tags = "")

public void AddAppConfigFromString(string appConfigContent)
{
_configurationDriver.SetConfigurationFormat(ConfigurationFormat.None);
_configurationFileDriver.SetConfigurationFormat(ConfigurationFormat.None);
_projectsDriver.AddFile("app.config", appConfigContent);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public ProjectFile GenerateStepDefinition(string methodName, string methodImplem
return GenerateStepDefinition(method);
}

public ProjectFile GenerateLoggingStepDefinition(string methodName, string pathToLogFile, string attributeName, string regex, ParameterType parameterType = ParameterType.Normal, string argumentName = null)
public ProjectFile GenerateLoggingStepDefinition(string methodName, string attributeName, string regex, ParameterType parameterType = ParameterType.Normal, string argumentName = null)
{
string method = GetLoggingStepDefinitionCode(methodName, attributeName, regex, parameterType, argumentName);
return GenerateStepDefinition(method);
Expand Down
Loading

0 comments on commit 77bea54

Please sign in to comment.