NUnitComposition.Core 1.0.0-beta002

Suggested Alternatives

Umbraco.Community.Integration.Tests.Extensions

Additional Details

This package has been renamed and released with the ID Umbraco.Community.Integration.Tests.Extensions.

This is a prerelease version of NUnitComposition.Core.
The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package NUnitComposition.Core --version 1.0.0-beta002
                    
NuGet\Install-Package NUnitComposition.Core -Version 1.0.0-beta002
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NUnitComposition.Core" Version="1.0.0-beta002" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NUnitComposition.Core" Version="1.0.0-beta002" />
                    
Directory.Packages.props
<PackageReference Include="NUnitComposition.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NUnitComposition.Core --version 1.0.0-beta002
                    
#r "nuget: NUnitComposition.Core, 1.0.0-beta002"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NUnitComposition.Core@1.0.0-beta002
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NUnitComposition.Core&version=1.0.0-beta002&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=NUnitComposition.Core&version=1.0.0-beta002&prerelease
                    
Install as a Cake Tool

NUnit Composition with Umbraco

Overview / Problem statement

This package has an [InjectionSource] and an [Inject] attribute that may be used to enrich any NUnit suite, but the [MakeOneTimeLifecycle] attribute is mainly targeted at Umbraco.

Umbraco publishes their own tests as NuGet packages for implementors to re-use instead of writing tons of setup code.

However, the Umbraco base classes set up and tear down the Umbraco instance for each test.
They may set up the database once per fixture, but each test gets a fresh Umbraco instance.
You'll have to track whether your own schema is created in your own setup method.

This is a problem if you want to run a large number of tests that all need the same schema.
This repository contains an example of how to work around this by "hacking" the NUnit pipeline and modifying the UmbracoIntegrationTest setup and teardown methods to be onetime variants.

Once the lifecycle is modified to run as one-time variants, we can utilize the [Inject] attribute to inject services from the Umbraco ServiceProvider to child tests in the scope.

Important attributes

The tern "scope fixture" is used to descibe an NUnit fixture with only OneTimeSetUp and OneTimeTearDown methods.

Attribute Description Dependencies
[ExtendableSetUpFixture] Replacement for [SetUpFixture] Allows IApplyToTest implementations to mutate the lifecycle methods via IExtendableLifecycle. Allows for further extension attributes to "get to do more". NUnit
[MakeOneTimeLifecycle] Moves [SetUp] and [TearDown] methods to one-time lifecycle. Necessary to use UmbracoIntegrationTest and others as base classes for scoped setup fixtures. NUnit
[InjectionSource] Allows a scope fixture to expose an IServiceProvider instance to child tests. NUnit
[Inject] Allows a test fixture to receive services from the closest [InjectionSource] in the hierarchy. NUnit

General Example

// TODO... 👼

Umbraco Example

There are two example "scoped" sets of tests in the FeatureA and FeatureB folders of the UmbracoTestsComposition project.

As with NUnit SetUpFixtures, the extandable setup fixture must be in the root namespace of the tests that need it.
Because there's a lot of singletons and stuff in Umbraco, it is likely not possible, and at least not recommended to have more than one scoped setup fixture per namespace, and no further ones in child namespaces.
As of writing Umbraco's base classes already specify [SingleThreaded] and [NonParallelizable].

An Umbraco-scoped setup fixture

namespace FeatureA;

[UmbracoTest(
    Database = UmbracoTestOptions.Database.NewSchemaPerFixture, 
    Logger = UmbracoTestOptions.Logger.Console
)]
[ExtendableSetUpFixture]
[MakeOneTimeLifecycle(
    [nameof(Setup), nameof(SetUp_Logging)],
    [nameof(TearDown), nameof(TearDownAsync), nameof(FixtureTearDown), nameof(TearDown_Logging)]
)]
[InjectionProvider(nameof(Services))]
public class FeatureAScope : UmbracoIntegrationTest
{
    public void StubForUmbracoTestDiscovery() {}

    public FeatureAScope()
    {
        // Umbraco's TestOptionAttributeBase looks for the UmbracoTest attribute via the current test method or its declaring type.
        // We need to set a dummy test method from this exact setup fixture.
        // It could possibly be done by sneaking it in to the first instance of onetime setups, but we still need a declared method on this type.
        this.ExposeUmbracoTestAttribute(nameof(StubForUmbracoTestDiscovery));
    }
}

A couple of test fixtures with access to the scoped setup fixture

[Inject(nameof(Inject))]
public class FeatureATests
{
    private IDataTypeService dataTypeService = null!;

    public void Inject(IDataTypeService dataTypeService)
    {
        this.dataTypeService = dataTypeService;
    }

    [Test]
    public async Task CanGetDataTypeFromInjectedService()
    {
        var allTypes = (await dataTypeService.GetAllAsync()).Take(3).ToList();
        Console.WriteLine($"We've got data types like {String.Join(',', allTypes.Select(x => x.Name))}...");
        Assert.That(allTypes, Has.Count.GreaterThan(0));
    }
}

[Inject(nameof(Inject))]
public class FeatureATestUsingSeveralServices
{
    private IDataTypeService dataTypeService = null!;
    private DataEditorCollection editorCollection = null!;
    private IConfigurationEditorJsonSerializer editorSerializer = null!;

    public void Inject(IDataTypeService dataTypeService, DataEditorCollection editorCollection, IConfigurationEditorJsonSerializer editorSerializer)
    {
        this.dataTypeService = dataTypeService;
        this.editorCollection = editorCollection;
        this.editorSerializer = editorSerializer;
    }

    [Test]
    public async Task CanCreateDataTypeUsingAllNecessaryServices()
    {
        var textBoxEditor = editorCollection.Single(x => x.Alias == Constants.PropertyEditors.Aliases.TextBox);
        var result = await dataTypeService.CreateAsync(
            new DataType(textBoxEditor, editorSerializer)
            {
                Name = "A test datatype"
            }, 
            Constants.Security.SuperUserKey);

        Assert.That(result.Success, Is.True, () => $"Failed with status {result.Status} and exception message {result.Exception?.Message ?? "<No exception thrown>"}");
    }
}

Snippets for re-usability with Umbraco

OneTimeUmbracoSetUp

public class OneTimeUmbracoSetUpAttribute() : MakeOneTimeLifecycleAttribute(
    [nameof(UmbracoIntegrationTest.Setup), nameof(UmbracoIntegrationTest.SetUp_Logging)],
    [nameof(UmbracoIntegrationTest.TearDown), nameof(UmbracoIntegrationTest.TearDownAsync), nameof(UmbracoIntegrationTest.FixtureTearDown), nameof(UmbracoIntegrationTest.TearDown_Logging)]
)
{
}

ServiceProviderAttribute

public class ServiceProviderAttribute() : InjectionProviderAttribute(nameof(IHost.Services)) { }

A basic scoped Umbraco instance

[UmbracoTest(
    Database = UmbracoTestOptions.Database.NewSchemaPerFixture, 
    Logger = UmbracoTestOptions.Logger.Console
)]
[ExtendableSetUpFixture]
[OneTimeUmbracoSetUp]
[ServiceProvider]
public class FeatureAScope : UmbracoIntegrationTest
{
}

Hopes and dreams

With Umbraco

  • Attribute for scope hierarchies utilizing ICoreScopeProvider and IServiceScope
  • Attribute transactions such that each test fixture or test can commit or roll back changes as needed
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated