Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for better coverage in Execution namespace #2042

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion Src/FluentAssertions/Common/Configuration.cs
Expand Up @@ -5,6 +5,11 @@ namespace FluentAssertions.Common;

public class Configuration
{
/// <summary>
/// Defines the key for the configuration of the test framework to be assumed in FluentAssertions.
/// </summary>
private const string TestFrameworkConfigurationKey = "FluentAssertions.TestFramework";

#region Private Definitions

private readonly object propertiesAccessLock = new();
Expand Down Expand Up @@ -118,7 +123,7 @@ public string TestFrameworkName
{
if (string.IsNullOrEmpty(testFrameworkName))
{
testFrameworkName = store.GetSetting("FluentAssertions.TestFramework");
testFrameworkName = store.GetSetting(TestFrameworkConfigurationKey);
}

return testFrameworkName;
Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Common/Services.cs
Expand Up @@ -46,6 +46,6 @@ public static void ResetToDefaults()
#else
ConfigurationStore = new NullConfigurationStore();
#endif
ThrowException = TestFrameworkProvider.Throw;
ThrowException = new TestFrameworkProvider(Configuration).Throw;
jnyrup marked this conversation as resolved.
Show resolved Hide resolved
}
}
49 changes: 28 additions & 21 deletions Src/FluentAssertions/Execution/TestFrameworkProvider.cs
Expand Up @@ -6,7 +6,10 @@

namespace FluentAssertions.Execution;

internal static class TestFrameworkProvider
/// <summary>
/// Implements a wrapper around all supported test frameworks to throw the correct assertion exception.
/// </summary>
internal class TestFrameworkProvider
{
#region Private Definitions

Expand All @@ -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()
Expand All @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions Src/FluentAssertions/Execution/XUnit2TestFramework.cs
Expand Up @@ -4,6 +4,9 @@

namespace FluentAssertions.Execution;

/// <summary>
/// Implements the XUnit (version 2) test framework adapter.
/// </summary>
internal class XUnit2TestFramework : ITestFramework
{
private Assembly assembly;
Expand Down
4 changes: 2 additions & 2 deletions Tests/FluentAssertions.Equivalency.Specs/TypedDataSetSpecs.cs
Expand Up @@ -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<string> excludedTales = new[] { "TypedDataTable1" };
IEnumerable<string> excludedTables = new[] { "TypedDataTable1" };
dataSet1.Should().BeEquivalentTo(dataSet2,
config => config.Excluding(dataSet => dataSet.HasErrors).ExcludingTables(excludedTales));
config => config.Excluding(dataSet => dataSet.HasErrors).ExcludingTables(excludedTables));
}

[Fact]
Expand Down
@@ -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<AssertionFailedException>()
.WithMessage("test message");
}
}
@@ -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<XunitException>();
}

[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<XunitException>();
}

[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<InvalidOperationException>()
.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<InvalidOperationException>()
.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<InvalidOperationException>()
.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;
}
}