diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt index 28a10d6..0e9f5af 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt @@ -10,6 +10,8 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0   # New Features - EXTENDED HostFixture class in the Codebelt.Extensions.Xunit.Hosting namespace to enable ValidateOnBuild and ValidateScopes when TFM is .NET 9 (or greater) and started the Host for consistency with AspNetCoreHostFixture +- EXTENDED IHostFixture interface in the Codebelt.Extensions.Xunit.Hosting namespace with two new methods: Dispose and DisposeAsync +- EXTENDED HostFixture class in the Codebelt.Extensions.Xunit.Hosting namespace with three new methods: InitializeAsync, OnDisposeManagedResourcesAsync, Dispose and DisposeAsync   Version 8.4.1 Availability: .NET 8, .NET 6 and .NET Standard 2.0 diff --git a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt index a98ff08..4ed08f4 100644 --- a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt @@ -5,6 +5,10 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0 - CHANGED Dependencies to latest and greatest with respect to TFMs - REMOVED Support for TFM .NET 6 (LTS)   +# New Features +- EXTENDED ITest interface in the Codebelt.Extensions.Xunit namespace with one new method: DisposeAsync +- EXTENDED Test class in the Codebelt.Extensions.Xunit namespace with three new methods: InitializeAsync, OnDisposeManagedResourcesAsync and DisposeAsync +  Version 8.4.0 Availability: .NET 8, .NET 6 and .NET Standard 2.0   diff --git a/CHANGELOG.md b/CHANGELOG.md index 84db6e8..6220636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ This major release is first and foremost focused on ironing out any wrinkles tha ### Added - StringExtensions class in the Codebelt.Extensions.Xunit namespace with one extension method (TFM netstandard2.0) for the String class: ReplaceLineEndings +- ITest interface in the Codebelt.Extensions.Xunit namespace was extended with one new method: DisposeAsync +- Test class in the Codebelt.Extensions.Xunit namespace was extended with three new methods: InitializeAsync, OnDisposeManagedResourcesAsync and DisposeAsync +- IHostFixture interface in the Codebelt.Extensions.Xunit.Hosting namespace was extended with two new methods: Dispose and DisposeAsync +- HostFixture class in the Codebelt.Extensions.Xunit.Hosting namespace was extended with three new methods: InitializeAsync, OnDisposeManagedResourcesAsync, Dispose and DisposeAsync ### Changed diff --git a/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj b/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj index 491973a..fd2dd45 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj +++ b/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj @@ -34,10 +34,6 @@ - - - - diff --git a/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs b/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs index b73414a..34a41d4 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs @@ -6,3 +6,4 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Major Code Smell", "S3881:\"IDisposable\" should be implemented correctly", Justification = "This is an implementation of the IDisposable interface tailored to avoid wrong implementations.", Scope = "type", Target = "~T:Codebelt.Extensions.Xunit.Hosting.HostFixture")] +[assembly: SuppressMessage("Major Code Smell", "S3971:\"GC.SuppressFinalize\" should not be called", Justification = "False-Positive due to IAsyncDisposable living side-by-side with IDisposable.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.HostFixture.DisposeAsync~System.Threading.Tasks.ValueTask")] diff --git a/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs index af3485a..340bfeb 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Xunit; namespace Codebelt.Extensions.Xunit.Hosting { @@ -11,7 +12,7 @@ namespace Codebelt.Extensions.Xunit.Hosting /// Provides a default implementation of the interface. /// /// - public class HostFixture : IDisposable, IHostFixture + public class HostFixture : IHostFixture, IAsyncLifetime { private readonly object _lock = new(); @@ -174,6 +175,34 @@ protected virtual void OnDisposeManagedResources() Host?.Dispose(); } + /// + /// Called when this object is being disposed by . + /// +#if NET8_0_OR_GREATER + protected virtual async ValueTask OnDisposeManagedResourcesAsync() + { + if (ServiceProvider is ServiceProvider sp) + { + await sp.DisposeAsync(); + } + + if (Host is IAsyncDisposable asyncDisposable) + { + await asyncDisposable.DisposeAsync(); + } + else + { + Host?.Dispose(); + } + } +#else + protected virtual ValueTask OnDisposeManagedResourcesAsync() + { + OnDisposeManagedResources(); + return default; + } +#endif + /// /// Called when this object is being disposed by either or and is false. /// @@ -208,5 +237,31 @@ protected void Dispose(bool disposing) Disposed = true; } } + + /// + /// Asynchronously releases the resources used by the . + /// + /// A that represents the asynchronous dispose operation. + /// https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method + public async ValueTask DisposeAsync() + { + await OnDisposeManagedResourcesAsync().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } + + /// + /// Called immediately after the class has been created, before it is used. + /// + /// A that represents the asynchronous operation. + public virtual Task InitializeAsync() + { + return Task.CompletedTask; + } + + Task IAsyncLifetime.DisposeAsync() + { + return DisposeAsync().AsTask(); + } } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs index c332b0d..515d746 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs @@ -5,26 +5,37 @@ namespace Codebelt.Extensions.Xunit.Hosting { - /// - /// Provides a way to use Microsoft Dependency Injection in unit tests. - /// - /// - public interface IHostFixture : IServiceTest, IHostTest, IConfigurationTest, IHostingEnvironmentTest - { #if NETSTANDARD2_0_OR_GREATER + public partial interface IHostFixture + { /// /// Gets or sets the delegate that adds configuration and environment information to a . /// /// The delegate that adds configuration and environment information to a . Action ConfigureCallback { get; set; } + } #else + public partial interface IHostFixture + { /// /// Gets or sets the delegate that adds configuration and environment information to a . /// /// The delegate that adds configuration and environment information to a . Action ConfigureCallback { get; set; } + } #endif + /// + /// Provides a way to use Microsoft Dependency Injection in unit tests. + /// + /// + /// + /// + /// + /// + /// + public partial interface IHostFixture : IServiceTest, IHostTest, IConfigurationTest, IHostingEnvironmentTest, IDisposable, IAsyncDisposable + { /// /// Gets or sets the delegate that adds services to the container. /// diff --git a/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj b/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj index 45e0624..caec1bb 100644 --- a/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj +++ b/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj @@ -11,9 +11,14 @@ - + + + + + + diff --git a/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs b/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs index fbdf1b5..8023644 100644 --- a/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs +++ b/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs @@ -6,3 +6,4 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Major Code Smell", "S3881:\"IDisposable\" should be implemented correctly", Justification = "This is a base class implementation of the IDisposable interface tailored to avoid wrong implementations.", Scope = "type", Target = "~T:Codebelt.Extensions.Xunit.Test")] +[assembly: SuppressMessage("Major Code Smell", "S3971:\"GC.SuppressFinalize\" should not be called", Justification = "False-Positive due to IAsyncDisposable living side-by-side with IDisposable.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Test.DisposeAsync~System.Threading.Tasks.ValueTask")] diff --git a/src/Codebelt.Extensions.Xunit/ITest.cs b/src/Codebelt.Extensions.Xunit/ITest.cs index 5d09798..b08272a 100644 --- a/src/Codebelt.Extensions.Xunit/ITest.cs +++ b/src/Codebelt.Extensions.Xunit/ITest.cs @@ -6,7 +6,7 @@ namespace Codebelt.Extensions.Xunit /// Represents the members needed for vanilla testing. /// /// - public interface ITest : IDisposable + public interface ITest : IDisposable, IAsyncDisposable { /// /// Gets the type of caller for this instance. Default is . diff --git a/src/Codebelt.Extensions.Xunit/Test.cs b/src/Codebelt.Extensions.Xunit/Test.cs index e8ce291..6994126 100644 --- a/src/Codebelt.Extensions.Xunit/Test.cs +++ b/src/Codebelt.Extensions.Xunit/Test.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Xunit; using Xunit.Abstractions; namespace Codebelt.Extensions.Xunit @@ -9,8 +11,10 @@ namespace Codebelt.Extensions.Xunit /// Represents the base class from which all implementations of unit testing should derive. /// /// - public abstract class Test : ITest + public abstract class Test : ITest, IAsyncLifetime { + private readonly object _lock = new(); + /// /// Provides a way, with wildcard support, to determine if matches . /// @@ -82,6 +86,14 @@ protected virtual void OnDisposeManagedResources() { } + /// + /// Called when this object is being disposed by . + /// + protected virtual ValueTask OnDisposeManagedResourcesAsync() + { + return default; + } + /// /// Called when this object is being disposed by either or and is false. /// @@ -105,12 +117,42 @@ public void Dispose() protected void Dispose(bool disposing) { if (Disposed) { return; } - if (disposing) + lock (_lock) { - OnDisposeManagedResources(); + if (Disposed) { return; } + if (disposing) + { + OnDisposeManagedResources(); + } + OnDisposeUnmanagedResources(); + Disposed = true; } - OnDisposeUnmanagedResources(); - Disposed = true; + } + + /// + /// Asynchronously releases the resources used by the . + /// + /// A that represents the asynchronous dispose operation. + /// https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method + public async ValueTask DisposeAsync() + { + await OnDisposeManagedResourcesAsync().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } + + /// + /// Called immediately after the class has been created, before it is used. + /// + /// A that represents the asynchronous operation. + public virtual Task InitializeAsync() + { + return Task.CompletedTask; + } + + Task IAsyncLifetime.DisposeAsync() + { + return DisposeAsync().AsTask(); } } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostFixtureTest.cs new file mode 100644 index 0000000..243fa39 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostFixtureTest.cs @@ -0,0 +1,65 @@ +using System; +using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; +using Microsoft.AspNetCore.Builder; +using Xunit; +using Xunit.Abstractions; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +{ + public class AspNetCoreHostFixtureTest : Test + { + public AspNetCoreHostFixtureTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void ConfigureHost_NullHostTest_ThrowsArgumentNullException() + { + // Arrange + var fixture = new AspNetCoreHostFixture(); + + // Act & Assert + Assert.Throws(() => fixture.ConfigureHost(null)); + } + + [Fact] + public void ConfigureHost_InvalidHostTestType_ThrowsArgumentOutOfRangeException() + { + // Arrange + var fixture = new AspNetCoreHostFixture(); + var invalidHostTest = new InvalidHostTest(fixture); + + // Act & Assert + Assert.Throws(() => fixture.ConfigureHost(invalidHostTest)); + } + + [Fact] + public void ConfigureApplicationCallback_SetAndGet_ReturnsCorrectValue() + { + // Arrange + var fixture = new AspNetCoreHostFixture(); + Action callback = app => { }; + + // Act + fixture.ConfigureApplicationCallback = callback; + + // Assert + Assert.Equal(callback, fixture.ConfigureApplicationCallback); + } + + [Fact] + public void ConfigureHost_ValidHostTest_ConfiguresHostCorrectly() + { + // Arrange + var fixture = new AspNetCoreHostFixture(); + var hostTest = new ValidHostTest(fixture); + + // Act + fixture.ConfigureHost(hostTest); + + // Assert + Assert.NotNull(fixture.Host); + Assert.NotNull(fixture.Application); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs new file mode 100644 index 0000000..c2ba881 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs @@ -0,0 +1,11 @@ +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +{ + public class InvalidHostTest : Test, IClassFixture where T : class, IHostFixture + { + public InvalidHostTest(T hostFixture) + { + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs new file mode 100644 index 0000000..544cc78 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +{ + public class ValidHostTest : AspNetCoreHostTest + { + public ValidHostTest(AspNetCoreHostFixture hostFixture) : base(hostFixture) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + + } + + public override void ConfigureApplication(IApplicationBuilder app) + { + + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj index 7f9809d..b7f7f06 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs new file mode 100644 index 0000000..9bc2e92 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs @@ -0,0 +1,11 @@ +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.Assets +{ + public class InvalidHostTest : Test, IClassFixture where T : class, IHostFixture + { + public InvalidHostTest(T hostFixture) + { + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs new file mode 100644 index 0000000..4a5d268 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Xunit.Abstractions; + +namespace Codebelt.Extensions.Xunit.Hosting.Assets +{ + public class ValidHostTest : HostTest + { + public ValidHostTest(HostFixture hostFixture) : base(hostFixture) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj index 6c49c08..2ad30d4 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostFixtureTest.cs new file mode 100644 index 0000000..d139fd2 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostFixtureTest.cs @@ -0,0 +1,58 @@ +using System; +using System.Threading.Tasks; +using Codebelt.Extensions.Xunit.Hosting.Assets; +using Xunit; +using Xunit.Abstractions; + +namespace Codebelt.Extensions.Xunit.Hosting +{ + public class HostFixtureTest : Test + { + private readonly HostFixture _hostFixture; + + public HostFixtureTest(ITestOutputHelper output) : base(output) + { + _hostFixture = new HostFixture(); + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentNullException_WhenHostTestIsNull() + { + Assert.Throws(() => _hostFixture.ConfigureHost(null)); + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotAssignableFromHostTest() + { + var invalidHostTest = new InvalidHostTest(new HostFixture()); + Assert.Throws(() => _hostFixture.ConfigureHost(invalidHostTest)); + } + + [Fact] + public void ConfigureHost_ShouldConfigureHostSuccessfully() + { + var validHostTest = new ValidHostTest(_hostFixture); + + _hostFixture.ConfigureHost(validHostTest); + + Assert.NotNull(_hostFixture.Host); + Assert.NotNull(_hostFixture.ServiceProvider); + Assert.NotNull(_hostFixture.Configuration); + Assert.NotNull(_hostFixture.HostingEnvironment); + } + + [Fact] + public void Dispose_ShouldDisposeResources() + { + _hostFixture.Dispose(); + Assert.True(_hostFixture.Disposed); + } + + [Fact] + public async Task DisposeAsync_ShouldDisposeResourcesAsync() + { + await _hostFixture.DisposeAsync(); + Assert.True(_hostFixture.Disposed); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs new file mode 100644 index 0000000..6adddb0 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; +using System.Threading.Tasks; + +namespace Codebelt.Extensions.Xunit.Assets +{ + public class AsyncDisposable : Test + { + IDisposable _disposableResource = new MemoryStream(); +#if NET8_0_OR_GREATER + IAsyncDisposable _asyncDisposableResource = new MemoryStream(); +#else + IAsyncDisposable _asyncDisposableResource = new WemoryStream(); +#endif + + protected override void OnDisposeManagedResources() + { + _disposableResource?.Dispose(); + _disposableResource = null; + DisposableResourceCalled = true; + } + + public bool DisposableResourceCalled { get; private set; } + + protected override async ValueTask OnDisposeManagedResourcesAsync() + { + if (_asyncDisposableResource is not null) + { + await _asyncDisposableResource.DisposeAsync().ConfigureAwait(false); + AsyncDisposableResourceCalled = true; + } + _asyncDisposableResource = null; + OnDisposeManagedResources(); + } + + public bool AsyncDisposableResourceCalled { get; private set; } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs new file mode 100644 index 0000000..eb02c50 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs @@ -0,0 +1,20 @@ +using System; +using System.IO; +using System.Threading.Tasks; + +namespace Codebelt.Extensions.Xunit.Assets +{ + public class WemoryStream : MemoryStream, IAsyncDisposable + { + protected virtual async ValueTask DisposeAsyncCore() + { + Dispose(false); + } + + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore(); + GC.SuppressFinalize(this); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs b/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs index e0646e9..22e2265 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Codebelt.Extensions.Xunit.Assets; using Xunit; using Xunit.Abstractions; @@ -11,7 +12,39 @@ public DisposableTest(ITestOutputHelper output) : base(output) { } +#if NET8_0_OR_GREATER + [Fact] + public async Task AsyncDisposable_VerifyThatAssetIsBeingDisposed() + { + AsyncDisposable ad = new AsyncDisposable(); + await using (ad.ConfigureAwait(false)) + { + Assert.NotNull(ad); + Assert.False(ad.DisposableResourceCalled); + Assert.False(ad.AsyncDisposableResourceCalled); + } + Assert.NotNull(ad); + Assert.True(ad.DisposableResourceCalled); + Assert.True(ad.AsyncDisposableResourceCalled); + } +#else + [Fact] + public async Task AsyncDisposable_VerifyThatAssetIsBeingDisposed() + { + AsyncDisposable ad = new AsyncDisposable(); + + Assert.NotNull(ad); + Assert.False(ad.DisposableResourceCalled); + Assert.False(ad.AsyncDisposableResourceCalled); + + await ad.DisposeAsync().ConfigureAwait(false); + + Assert.NotNull(ad); + Assert.True(ad.DisposableResourceCalled); + Assert.True(ad.AsyncDisposableResourceCalled); + } +#endif [Fact] public void ManagedDisposable_VerifyThatAssetIsBeingDisposed() diff --git a/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs b/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs index 333b708..53edd5c 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; using Xunit.Sdk; @@ -9,11 +10,30 @@ public class TestTest : Test { private const string ExpectedStringValue = "AllIsGood"; private bool _onDisposeManagedResourcesCalled; + private bool _initializeAsyncCalled; public TestTest(ITestOutputHelper output) : base(output) { } + public override Task InitializeAsync() + { + _initializeAsyncCalled = true; + return Task.CompletedTask; + } + + protected override ValueTask OnDisposeManagedResourcesAsync() + { + TestOutput.WriteLine($"{nameof(IAsyncLifetime.DisposeAsync)} was called."); + return default; + } + + [Fact] + public void Test_InitializeAsyncCalled_ShouldBeTrue() + { + Assert.True(_initializeAsyncCalled); + } + [Fact] public void Test_ShouldHaveTestOutput() {