From b79a087a6448d7077fc9c82cfa9d1e73c410b7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Gr=C3=BCtzmacher?= <44983012+lg2de@users.noreply.github.com> Date: Sat, 21 Jan 2023 13:38:54 +0100 Subject: [PATCH] Add unit tests for better coverage in Execution namespace (#2042) --- Src/FluentAssertions/Common/Configuration.cs | 7 +- Src/FluentAssertions/Common/Services.cs | 2 +- .../Execution/TestFrameworkProvider.cs | 49 +++++---- .../Execution/XUnit2TestFramework.cs | 3 + .../TypedDataSetSpecs.cs | 4 +- .../Execution/FallbackTestFrameworkTests.cs | 24 +++++ .../Execution/TestFrameworkProviderTests.cs | 99 +++++++++++++++++++ 7 files changed, 163 insertions(+), 25 deletions(-) create mode 100644 Tests/FluentAssertions.Specs/Execution/FallbackTestFrameworkTests.cs create mode 100644 Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs diff --git a/Src/FluentAssertions/Common/Configuration.cs b/Src/FluentAssertions/Common/Configuration.cs index ed6b48c28e..793f770cc5 100644 --- a/Src/FluentAssertions/Common/Configuration.cs +++ b/Src/FluentAssertions/Common/Configuration.cs @@ -5,6 +5,11 @@ namespace FluentAssertions.Common; public class Configuration { + /// + /// Defines the key for the configuration of the test framework to be assumed in FluentAssertions. + /// + private const string TestFrameworkConfigurationKey = "FluentAssertions.TestFramework"; + #region Private Definitions private readonly object propertiesAccessLock = new(); @@ -118,7 +123,7 @@ public string TestFrameworkName { if (string.IsNullOrEmpty(testFrameworkName)) { - testFrameworkName = store.GetSetting("FluentAssertions.TestFramework"); + testFrameworkName = store.GetSetting(TestFrameworkConfigurationKey); } return testFrameworkName; diff --git a/Src/FluentAssertions/Common/Services.cs b/Src/FluentAssertions/Common/Services.cs index 7b461caf45..740bf428a3 100644 --- a/Src/FluentAssertions/Common/Services.cs +++ b/Src/FluentAssertions/Common/Services.cs @@ -46,6 +46,6 @@ public static void ResetToDefaults() #else ConfigurationStore = new NullConfigurationStore(); #endif - ThrowException = TestFrameworkProvider.Throw; + ThrowException = new TestFrameworkProvider(Configuration).Throw; } } diff --git a/Src/FluentAssertions/Execution/TestFrameworkProvider.cs b/Src/FluentAssertions/Execution/TestFrameworkProvider.cs index 684e46eee7..b8278a6d6e 100644 --- a/Src/FluentAssertions/Execution/TestFrameworkProvider.cs +++ b/Src/FluentAssertions/Execution/TestFrameworkProvider.cs @@ -6,7 +6,10 @@ namespace FluentAssertions.Execution; -internal static class TestFrameworkProvider +/// +/// Implements a wrapper around all supported test frameworks to throw the correct assertion exception. +/// +internal class TestFrameworkProvider { #region Private Definitions @@ -19,22 +22,25 @@ internal static class TestFrameworkProvider ["xunit2"] = new XUnit2TestFramework() // Keep this the last one as it uses a try/catch approach }; - private static ITestFramework testFramework; + private readonly Configuration configuration; + + private ITestFramework testFramework; #endregion - [DoesNotReturn] - public static void Throw(string message) + public TestFrameworkProvider(Configuration configuration) { - if (testFramework is null) - { - testFramework = DetectFramework(); - } + this.configuration = configuration; + } + [DoesNotReturn] + public void Throw(string message) + { + testFramework ??= DetectFramework(); testFramework.Throw(message); } - private static ITestFramework DetectFramework() + private ITestFramework DetectFramework() { ITestFramework detectedFramework = AttemptToDetectUsingAppSetting() ?? AttemptToDetectUsingDynamicScanning() @@ -43,9 +49,9 @@ private static ITestFramework DetectFramework() return detectedFramework; } - private static ITestFramework AttemptToDetectUsingAppSetting() + private ITestFramework AttemptToDetectUsingAppSetting() { - string frameworkName = Services.Configuration.TestFrameworkName; + string frameworkName = configuration.TestFrameworkName; if (string.IsNullOrEmpty(frameworkName)) { return null; @@ -54,22 +60,23 @@ private static ITestFramework AttemptToDetectUsingAppSetting() if (!Frameworks.TryGetValue(frameworkName, out ITestFramework framework)) { string frameworks = string.Join(", ", Frameworks.Keys); - var message = $"FluentAssertions was configured to use {frameworkName} but the requested test framework is not supported. " + - $"Please use one of the supported frameworks: {frameworks}"; + var message = $"FluentAssertions was configured to use the test framework '{frameworkName}' but this is not supported. " + + $"Please use one of the supported frameworks: {frameworks}."; - throw new Exception(message); + throw new InvalidOperationException(message); } if (!framework.IsAvailable) { string frameworks = string.Join(", ", Frameworks.Keys); - var message = framework is LateBoundTestFramework lateBoundTestFramework - ? $"FluentAssertions was configured to use {frameworkName} but the required test framework assembly {lateBoundTestFramework.AssemblyName} could not be found. " + - $"Please use one of the supported frameworks: {frameworks}" - : $"FluentAssertions was configured to use {frameworkName} but the required test framework could not be found. " + - $"Please use one of the supported frameworks: {frameworks}"; - - throw new Exception(message); + var innerMessage = framework is LateBoundTestFramework lateBoundTestFramework + ? $"the required assembly '{lateBoundTestFramework.AssemblyName}' could not be found" + : "it could not be found"; + var message = + $"FluentAssertions was configured to use the test framework '{frameworkName}' but {innerMessage}. " + + $"Please use one of the supported frameworks: {frameworks}."; + + throw new InvalidOperationException(message); } return framework; diff --git a/Src/FluentAssertions/Execution/XUnit2TestFramework.cs b/Src/FluentAssertions/Execution/XUnit2TestFramework.cs index 5d934fa19e..776148b64b 100644 --- a/Src/FluentAssertions/Execution/XUnit2TestFramework.cs +++ b/Src/FluentAssertions/Execution/XUnit2TestFramework.cs @@ -4,6 +4,9 @@ namespace FluentAssertions.Execution; +/// +/// Implements the XUnit (version 2) test framework adapter. +/// internal class XUnit2TestFramework : ITestFramework { private Assembly assembly; diff --git a/Tests/FluentAssertions.Equivalency.Specs/TypedDataSetSpecs.cs b/Tests/FluentAssertions.Equivalency.Specs/TypedDataSetSpecs.cs index 62a6a046f4..53649b85ad 100644 --- a/Tests/FluentAssertions.Equivalency.Specs/TypedDataSetSpecs.cs +++ b/Tests/FluentAssertions.Equivalency.Specs/TypedDataSetSpecs.cs @@ -236,9 +236,9 @@ public void When_HasErrors_does_not_match_and_property_is_excluded_as_list_it_sh dataSet2.TypedDataTable1.Rows[0].RowError = "Manually added error"; // Act & Assert - IEnumerable excludedTales = new[] { "TypedDataTable1" }; + IEnumerable excludedTables = new[] { "TypedDataTable1" }; dataSet1.Should().BeEquivalentTo(dataSet2, - config => config.Excluding(dataSet => dataSet.HasErrors).ExcludingTables(excludedTales)); + config => config.Excluding(dataSet => dataSet.HasErrors).ExcludingTables(excludedTables)); } [Fact] diff --git a/Tests/FluentAssertions.Specs/Execution/FallbackTestFrameworkTests.cs b/Tests/FluentAssertions.Specs/Execution/FallbackTestFrameworkTests.cs new file mode 100644 index 0000000000..f8231e0898 --- /dev/null +++ b/Tests/FluentAssertions.Specs/Execution/FallbackTestFrameworkTests.cs @@ -0,0 +1,24 @@ +using FluentAssertions.Execution; +using Xunit; + +namespace FluentAssertions.Specs.Execution; + +public class FallbackTestFrameworkTests +{ + [Fact] + public void The_fallback_test_framework_is_available() + { + var sut = new FallbackTestFramework(); + + sut.IsAvailable.Should().BeTrue(); + } + + [Fact] + public void Throwing_with_messages_throws_the_exception() + { + var sut = new FallbackTestFramework(); + + sut.Invoking(x => x.Throw("test message")).Should().ThrowExactly() + .WithMessage("test message"); + } +} diff --git a/Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs b/Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs new file mode 100644 index 0000000000..d6b1426d9d --- /dev/null +++ b/Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs @@ -0,0 +1,99 @@ +using System; +using FluentAssertions.Common; +using FluentAssertions.Execution; +using Xunit; +using Xunit.Sdk; + +namespace FluentAssertions.Specs.Execution; + +public class TestFrameworkProviderTests +{ + [Fact] + public void When_running_xunit_test_implicitly_it_should_be_detected() + { + // Arrange + var configuration = new Configuration(new TestConfigurationStore()); + var testFrameworkProvider = new TestFrameworkProvider(configuration); + + // Act + Action act = () => testFrameworkProvider.Throw("MyMessage"); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void When_running_xunit_test_explicitly_it_should_be_detected() + { + // Arrange + var configuration = new Configuration(new TestConfigurationStore()) + { + TestFrameworkName = "xunit2" + }; + var testFrameworkProvider = new TestFrameworkProvider(configuration); + + // Act + Action act = () => testFrameworkProvider.Throw("MyMessage"); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void When_running_test_with_unknown_test_framework_it_should_throw() + { + // Arrange + var configuration = new Configuration(new TestConfigurationStore()) + { + TestFrameworkName = "foo" + }; + var testFrameworkProvider = new TestFrameworkProvider(configuration); + + // Act + Action act = () => testFrameworkProvider.Throw("MyMessage"); + + // Assert + act.Should().Throw() + .WithMessage("*the test framework 'foo' but this is not supported*"); + } + + [Fact] + public void When_running_test_with_direct_bound_but_unavailable_test_framework_it_should_throw() + { + // Arrange + var configuration = new Configuration(new TestConfigurationStore()) + { + TestFrameworkName = "nspec3" + }; + var testFrameworkProvider = new TestFrameworkProvider(configuration); + + // Act + Action act = () => testFrameworkProvider.Throw("MyMessage"); + + // Assert + act.Should().Throw() + .WithMessage("*test framework 'nspec3' but it could not be found*"); + } + + [Fact] + public void When_running_test_with_late_bound_but_unavailable_test_framework_it_should_throw() + { + // Arrange + var configuration = new Configuration(new TestConfigurationStore()) + { + TestFrameworkName = "nunit" + }; + var testFrameworkProvider = new TestFrameworkProvider(configuration); + + // Act + Action act = () => testFrameworkProvider.Throw("MyMessage"); + + act.Should().Throw() + .WithMessage("*test framework 'nunit' but the required assembly 'nunit.framework' could not be found*"); + } + + private sealed class TestConfigurationStore : IConfigurationStore + { + string IConfigurationStore.GetSetting(string name) => string.Empty; + } +}