diff --git a/Src/FluentAssertions/Common/Configuration.cs b/Src/FluentAssertions/Common/Configuration.cs index ed6b48c28e..a614eaf9ce 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. + /// + internal 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/Execution/TestFrameworkProvider.cs b/Src/FluentAssertions/Execution/TestFrameworkProvider.cs index 684e46eee7..49f88ad5af 100644 --- a/Src/FluentAssertions/Execution/TestFrameworkProvider.cs +++ b/Src/FluentAssertions/Execution/TestFrameworkProvider.cs @@ -6,6 +6,9 @@ namespace FluentAssertions.Execution; +/// +/// Implements a wrapper around all supported test frameworks to throw the correct assertion exception. +/// internal static class TestFrameworkProvider { #region Private Definitions @@ -28,24 +31,24 @@ public static void Throw(string message) { if (testFramework is null) { - testFramework = DetectFramework(); + testFramework = DetectFramework(Services.Configuration); } testFramework.Throw(message); } - private static ITestFramework DetectFramework() + internal static ITestFramework DetectFramework(Configuration configuration) { - ITestFramework detectedFramework = AttemptToDetectUsingAppSetting() + ITestFramework detectedFramework = AttemptToDetectUsingAppSetting(configuration) ?? AttemptToDetectUsingDynamicScanning() ?? new FallbackTestFramework(); return detectedFramework; } - private static ITestFramework AttemptToDetectUsingAppSetting() + internal static ITestFramework AttemptToDetectUsingAppSetting(Configuration configuration) { - string frameworkName = Services.Configuration.TestFrameworkName; + string frameworkName = configuration.TestFrameworkName; if (string.IsNullOrEmpty(frameworkName)) { return null; @@ -54,22 +57,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/Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs b/Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs new file mode 100644 index 0000000000..ffe7e94ea8 --- /dev/null +++ b/Tests/FluentAssertions.Specs/Execution/TestFrameworkProviderTests.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using FluentAssertions.Common; +using FluentAssertions.Execution; +using Xunit; + +namespace FluentAssertions.Specs.Execution; + +public class TestFrameworkProviderTests +{ + [Fact] + public void When_running_xunit_test_implicitly_it_should_be_detected() + { + var configuration = new Configuration(new TestConfigurationStore()); + var result = TestFrameworkProvider.DetectFramework(configuration); + + result.IsAvailable.Should().BeTrue(); + result.Should().BeOfType(); + } + + [Fact] + public void When_running_xunit_test_explicitly_it_should_be_detected() + { + var configurationStore = new TestConfigurationStore { Data = { [Configuration.TestFrameworkConfigurationKey] = "xunit2" } }; + var configuration = new Configuration(configurationStore); + var result = TestFrameworkProvider.DetectFramework(configuration); + + result.IsAvailable.Should().BeTrue(); + result.Should().BeOfType(); + } + + [Fact] + public void When_running_test_with_unknown_test_framework_it_should_throw() + { + var configurationStore = new TestConfigurationStore { Data = { [Configuration.TestFrameworkConfigurationKey] = "foo" } }; + var configuration = new Configuration(configurationStore); + + this.Invoking(_ => TestFrameworkProvider.AttemptToDetectUsingAppSetting(configuration)) + .Should().Throw() + .WithMessage("FluentAssertions was configured to use the test framework 'foo' but this is not supported." + + " Please use one of the supported frameworks: mspec, nspec3, nunit, mstestv2, xunit2."); + } + + [Fact] + public void When_running_test_with_direct_bound_but_unavailable_test_framework_it_should_throw() + { + var configurationStore = new TestConfigurationStore { Data = { [Configuration.TestFrameworkConfigurationKey] = "nspec3" } }; + var configuration = new Configuration(configurationStore); + + this.Invoking(_ => TestFrameworkProvider.AttemptToDetectUsingAppSetting(configuration)) + .Should().Throw() + .WithMessage("FluentAssertions was configured to use the test framework 'nspec3' but it could not be found." + + " Please use one of the supported frameworks: mspec, nspec3, nunit, mstestv2, xunit2."); + } + + [Fact] + public void When_running_test_with_late_bound_but_unavailable_test_framework_it_should_throw() + { + var configurationStore = new TestConfigurationStore { Data = { [Configuration.TestFrameworkConfigurationKey] = "nunit" } }; + var configuration = new Configuration(configurationStore); + + this.Invoking(_ => TestFrameworkProvider.AttemptToDetectUsingAppSetting(configuration)) + .Should().Throw() + .WithMessage("FluentAssertions was configured to use the test framework 'nunit' but the required assembly 'nunit.framework' could not be found." + + " Please use one of the supported frameworks: mspec, nspec3, nunit, mstestv2, xunit2."); + } + + private class TestConfigurationStore : IConfigurationStore + { + public IDictionary Data { get; } = new Dictionary(); + + public string GetSetting(string name) + { + Data.TryGetValue(name, out var setting); + return setting ?? string.Empty; + } + } +}