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;
+ }
+}