diff --git a/src/Umbraco.Tests/Testing/TestOptionAttributeBase.cs b/src/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs
similarity index 88%
rename from src/Umbraco.Tests/Testing/TestOptionAttributeBase.cs
rename to src/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs
index 2fb4660481..bbfa68778f 100644
--- a/src/Umbraco.Tests/Testing/TestOptionAttributeBase.cs
+++ b/src/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs
@@ -31,10 +31,14 @@ namespace Umbraco.Tests.Testing
var test = TestContext.CurrentContext.Test;
var typeName = test.ClassName;
var methodName = test.MethodName;
+ // this will only get types from whatever is already loaded in the app domain
var type = Type.GetType(typeName, false);
if (type == null)
{
- type = ScanAssemblies
+ // automatically add the executing and calling assemblies to the list to scan for this type
+ var scanAssemblies = ScanAssemblies.Union(new[] {Assembly.GetExecutingAssembly(), Assembly.GetCallingAssembly()}).ToList();
+
+ type = scanAssemblies
.Select(assembly => assembly.GetType(typeName, false))
.FirstOrDefault(x => x != null);
if (type == null)
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestAttribute.cs b/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs
similarity index 100%
rename from src/Umbraco.Tests/Testing/UmbracoTestAttribute.cs
rename to src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs
diff --git a/src/Umbraco.Tests.Common/Testing/UmbracoTestOptions.cs b/src/Umbraco.Tests.Common/Testing/UmbracoTestOptions.cs
new file mode 100644
index 0000000000..eef6e45d7e
--- /dev/null
+++ b/src/Umbraco.Tests.Common/Testing/UmbracoTestOptions.cs
@@ -0,0 +1,61 @@
+namespace Umbraco.Tests.Testing
+{
+ public static class UmbracoTestOptions
+ {
+ public enum Logger
+ {
+ ///
+ /// pure mocks
+ ///
+ Mock,
+ ///
+ /// Serilog for tests
+ ///
+ Serilog,
+ ///
+ /// console logger
+ ///
+ Console
+ }
+
+ public enum Database
+ {
+ ///
+ /// no database
+ ///
+ None,
+ ///
+ /// new empty database file for the entire fixture
+ ///
+ NewEmptyPerFixture,
+ ///
+ /// new empty database file per test
+ ///
+ NewEmptyPerTest,
+ ///
+ /// new database file with schema for the entire fixture
+ ///
+ NewSchemaPerFixture,
+ ///
+ /// new database file with schema per test
+ ///
+ NewSchemaPerTest
+ }
+
+ public enum TypeLoader
+ {
+ ///
+ /// the default, global type loader for tests
+ ///
+ Default,
+ ///
+ /// create one type loader for the feature
+ ///
+ PerFixture,
+ ///
+ /// create one type loader for each test
+ ///
+ PerTest
+ }
+ }
+}
diff --git a/src/Umbraco.Tests.Integration/ContainerTests.cs b/src/Umbraco.Tests.Integration/ContainerTests.cs
index 945eeda2f0..34a32a38a8 100644
--- a/src/Umbraco.Tests.Integration/ContainerTests.cs
+++ b/src/Umbraco.Tests.Integration/ContainerTests.cs
@@ -13,6 +13,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence;
using Umbraco.Tests.Common;
using Umbraco.Tests.Integration.Implementations;
+using Umbraco.Tests.Integration.Testing;
namespace Umbraco.Tests.Integration
{
@@ -82,7 +83,7 @@ namespace Umbraco.Tests.Integration
// it means the container won't be disposed, and maybe other services? not sure.
// In cases where we use it can we use IConfigureOptions? https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/
- var umbracoContainer = RuntimeTests.GetUmbracoContainer(out var serviceProviderFactory);
+ var umbracoContainer = UmbracoIntegrationTest.GetUmbracoContainer(out var serviceProviderFactory);
IHostApplicationLifetime lifetime1 = null;
diff --git a/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs
new file mode 100644
index 0000000000..553aa4fe85
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Data.Common;
+using System.Data.SqlClient;
+using System.IO;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using NUnit.Framework;
+using Umbraco.Configuration.Models;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence;
+using Umbraco.Tests.Integration.Testing;
+using Umbraco.Tests.Testing;
+
+namespace Umbraco.Tests.Integration.Extensions
+{
+ public static class ApplicationBuilderExtensions
+ {
+ ///
+ /// Creates a LocalDb instance to use for the test
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseTestLocalDb(this IApplicationBuilder app,
+ string dbFilePath,
+ UmbracoIntegrationTest integrationTest)
+ {
+ // get the currently set db options
+ var testOptions = TestOptionAttributeBase.GetTestOptions();
+
+ if (testOptions.Database == UmbracoTestOptions.Database.None)
+ return app;
+
+ // need to manually register this factory
+ DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);
+
+ if (!Directory.Exists(dbFilePath))
+ Directory.CreateDirectory(dbFilePath);
+
+ var db = UmbracoIntegrationTest.GetOrCreate(dbFilePath,
+ app.ApplicationServices.GetRequiredService(),
+ app.ApplicationServices.GetRequiredService(),
+ app.ApplicationServices.GetRequiredService());
+
+ switch (testOptions.Database)
+ {
+ case UmbracoTestOptions.Database.NewSchemaPerTest:
+
+ // Add teardown callback
+ integrationTest.OnTestTearDown(() => db.Detach());
+
+ // New DB + Schema
+ db.AttachSchema();
+
+ // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
+ var dbFactory = app.ApplicationServices.GetRequiredService();
+ if (!dbFactory.Configured)
+ {
+ dbFactory.Configure(db.ConnectionString, Umbraco.Core.Constants.DatabaseProviders.SqlServer);
+ }
+
+ // In the case that we've initialized the schema, it means that we are installed so we'll want to ensure that
+ // the runtime state is configured correctly so we'll force update the configuration flag and re-run the
+ // runtime state checker.
+ // TODO: This wouldn't be required if we don't store the Umbraco version in config
+
+ // right now we are an an 'Install' state
+ var runtimeState = (RuntimeState)app.ApplicationServices.GetRequiredService();
+ Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
+
+ // dynamically change the config status
+ var umbVersion = app.ApplicationServices.GetRequiredService();
+ var config = app.ApplicationServices.GetRequiredService();
+ config[GlobalSettings.Prefix + "ConfigurationStatus"] = umbVersion.SemanticVersion.ToString();
+
+ // re-run the runtime level check
+ var profilingLogger = app.ApplicationServices.GetRequiredService();
+ runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger);
+
+ Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
+
+ break;
+ case UmbracoTestOptions.Database.NewEmptyPerTest:
+
+ // Add teardown callback
+ integrationTest.OnTestTearDown(() => db.Detach());
+
+ db.AttachEmpty();
+
+ break;
+ case UmbracoTestOptions.Database.NewSchemaPerFixture:
+
+ // Add teardown callback
+ integrationTest.OnFixtureTearDown(() => db.Detach());
+
+ break;
+ case UmbracoTestOptions.Database.NewEmptyPerFixture:
+
+ // Add teardown callback
+ integrationTest.OnFixtureTearDown(() => db.Detach());
+
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(testOptions), testOptions, null);
+ }
+
+ return app;
+ }
+
+ }
+
+
+}
diff --git a/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs b/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000000..9dde20036b
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Tests.Integration.Implementations;
+
+namespace Umbraco.Tests.Integration.Extensions
+{
+ public static class ServiceCollectionExtensions
+ {
+ ///
+ /// These services need to be manually added because they do not get added by the generic host
+ ///
+ ///
+ ///
+ ///
+ public static void AddRequiredNetCoreServices(this IServiceCollection services, TestHelper testHelper, IWebHostEnvironment webHostEnvironment)
+ {
+ services.AddSingleton(x => testHelper.GetHttpContextAccessor());
+ // the generic host does add IHostEnvironment but not this one because we are not actually in a web context
+ services.AddSingleton(x => webHostEnvironment);
+ }
+ }
+}
diff --git a/src/Umbraco.Tests.Integration/Implementations/ApplicationBuilderExtensions.cs b/src/Umbraco.Tests.Integration/Implementations/ApplicationBuilderExtensions.cs
deleted file mode 100644
index abb22c0bd7..0000000000
--- a/src/Umbraco.Tests.Integration/Implementations/ApplicationBuilderExtensions.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Data.Common;
-using System.Data.SqlClient;
-using System.IO;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using NUnit.Framework;
-using Umbraco.Configuration.Models;
-using Umbraco.Core;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Persistence;
-using Umbraco.Tests.Integration.Testing;
-
-namespace Umbraco.Tests.Integration.Implementations
-{
- public static class ApplicationBuilderExtensions
- {
- ///
- /// Creates a LocalDb instance to use for the test
- ///
- ///
- ///
- ///
- /// Default is true - meaning a brand new database is created for this test. If this is false it will try to
- /// re-use an existing database that was already created as part of this test fixture.
- /// // TODO Implement the 'false' behavior
- ///
- ///
- /// Default is true - meaning a database schema will be created for this test if it's a new database. If this is false
- /// it will just create an empty database.
- ///
- ///
- public static IApplicationBuilder UseTestLocalDb(this IApplicationBuilder app,
- string dbFilePath,
- bool createNewDb = true,
- bool initializeSchema = true)
- {
- // need to manually register this factory
- DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);
-
- if (!Directory.Exists(dbFilePath))
- Directory.CreateDirectory(dbFilePath);
-
- var db = LocalDbTestDatabase.Get(dbFilePath,
- app.ApplicationServices.GetRequiredService(),
- app.ApplicationServices.GetRequiredService(),
- app.ApplicationServices.GetRequiredService());
-
- if (initializeSchema)
- {
- // New DB + Schema
- db.AttachSchema();
-
- // In the case that we've initialized the schema, it means that we are installed so we'll want to ensure that
- // the runtime state is configured correctly so we'll force update the configuration flag and re-run the
- // runtime state checker.
- // TODO: This wouldn't be required if we don't store the Umbraco version in config
-
- // right now we are an an 'Install' state
- var runtimeState = (RuntimeState)app.ApplicationServices.GetRequiredService();
- Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
-
- // dynamically change the config status
- var umbVersion = app.ApplicationServices.GetRequiredService();
- var config = app.ApplicationServices.GetRequiredService();
- config[GlobalSettings.Prefix + "ConfigurationStatus"] = umbVersion.SemanticVersion.ToString();
-
- // re-run the runtime level check
- var dbFactory = app.ApplicationServices.GetRequiredService();
- var profilingLogger = app.ApplicationServices.GetRequiredService();
- runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger);
-
- Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
-
- }
- else
- {
- db.AttachEmpty();
- }
-
- return app;
- }
-
- }
-
-
-}
diff --git a/src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs
similarity index 72%
rename from src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs
rename to src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs
index 49e48e0a2f..e92653fb98 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs
+++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs
@@ -1,29 +1,29 @@
using System.Linq;
using NUnit.Framework;
+using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Scoping;
-using Umbraco.Tests.TestHelpers;
+using Umbraco.Tests.Integration.Testing;
using Umbraco.Tests.Testing;
-using Umbraco.Core;
-namespace Umbraco.Tests.Persistence.Repositories
+namespace Umbraco.Tests.Integration.Persistence.Repositories
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
- public class AuditRepositoryTest : TestWithDatabaseBase
+ public class AuditRepositoryTest : UmbracoIntegrationTest
{
[Test]
public void Can_Add_Audit_Entry()
{
- var sp = TestObjects.GetScopeProvider(Logger);
- using (var scope = sp.CreateScope())
+ var sp = ScopeProvider;
+ using (var scope = ScopeProvider.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
- repo.Save(new AuditItem(-1, AuditType.System, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), "This is a System audit trail"));
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
+ repo.Save(new AuditItem(-1, AuditType.System, -1, UmbracoObjectTypes.Document.GetName(), "This is a System audit trail"));
var dtos = scope.Database.Fetch("WHERE id > -1");
@@ -35,15 +35,15 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void Get_Paged_Items()
{
- var sp = TestObjects.GetScopeProvider(Logger);
+ var sp = ScopeProvider;
using (var scope = sp.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
for (var i = 0; i < 100; i++)
{
- repo.Save(new AuditItem(i, AuditType.New, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), $"Content {i} created"));
- repo.Save(new AuditItem(i, AuditType.Publish, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), $"Content {i} published"));
+ repo.Save(new AuditItem(i, AuditType.New, -1, UmbracoObjectTypes.Document.GetName(), $"Content {i} created"));
+ repo.Save(new AuditItem(i, AuditType.Publish, -1, UmbracoObjectTypes.Document.GetName(), $"Content {i} published"));
}
scope.Complete();
@@ -51,7 +51,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var scope = sp.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
var page = repo.GetPagedResultsByQuery(sp.SqlContext.Query(), 0, 10, out var total, Direction.Descending, null, null);
@@ -63,15 +63,15 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void Get_Paged_Items_By_User_Id_With_Query_And_Filter()
{
- var sp = TestObjects.GetScopeProvider(Logger);
+ var sp = ScopeProvider;
using (var scope = sp.CreateScope())
{
var repo = new AuditRepository((IScopeAccessor)sp, Logger);
for (var i = 0; i < 100; i++)
{
- repo.Save(new AuditItem(i, AuditType.New, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), $"Content {i} created"));
- repo.Save(new AuditItem(i, AuditType.Publish, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), $"Content {i} published"));
+ repo.Save(new AuditItem(i, AuditType.New, -1, UmbracoObjectTypes.Document.GetName(), $"Content {i} created"));
+ repo.Save(new AuditItem(i, AuditType.Publish, -1, UmbracoObjectTypes.Document.GetName(), $"Content {i} published"));
}
scope.Complete();
@@ -106,15 +106,15 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void Get_Paged_Items_With_AuditType_Filter()
{
- var sp = TestObjects.GetScopeProvider(Logger);
+ var sp = ScopeProvider;
using (var scope = sp.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
for (var i = 0; i < 100; i++)
{
- repo.Save(new AuditItem(i, AuditType.New, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), $"Content {i} created"));
- repo.Save(new AuditItem(i, AuditType.Publish, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), $"Content {i} published"));
+ repo.Save(new AuditItem(i, AuditType.New, -1, UmbracoObjectTypes.Document.GetName(), $"Content {i} created"));
+ repo.Save(new AuditItem(i, AuditType.Publish, -1, UmbracoObjectTypes.Document.GetName(), $"Content {i} published"));
}
scope.Complete();
@@ -122,10 +122,10 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var scope = sp.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
var page = repo.GetPagedResultsByQuery(sp.SqlContext.Query(), 0, 9, out var total, Direction.Descending,
- new[] {AuditType.Publish}, null)
+ new[] { AuditType.Publish }, null)
.ToArray();
Assert.AreEqual(9, page.Length);
@@ -137,15 +137,15 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void Get_Paged_Items_With_Custom_Filter()
{
- var sp = TestObjects.GetScopeProvider(Logger);
+ var sp = ScopeProvider;
using (var scope = sp.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
for (var i = 0; i < 100; i++)
{
- repo.Save(new AuditItem(i, AuditType.New, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), "Content created"));
- repo.Save(new AuditItem(i, AuditType.Publish, -1, ObjectTypes.GetName(UmbracoObjectTypes.Document), "Content published"));
+ repo.Save(new AuditItem(i, AuditType.New, -1, UmbracoObjectTypes.Document.GetName(), "Content created"));
+ repo.Save(new AuditItem(i, AuditType.Publish, -1, UmbracoObjectTypes.Document.GetName(), "Content published"));
}
scope.Complete();
@@ -153,7 +153,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var scope = sp.CreateScope())
{
- var repo = new AuditRepository((IScopeAccessor) sp, Logger);
+ var repo = new AuditRepository((IScopeAccessor)sp, Logger);
var page = repo.GetPagedResultsByQuery(sp.SqlContext.Query(), 0, 8, out var total, Direction.Descending,
null, sp.SqlContext.Query().Where(item => item.Comment == "Content created"))
diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs
index 814687eb7f..210f767de1 100644
--- a/src/Umbraco.Tests.Integration/RuntimeTests.cs
+++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs
@@ -1,30 +1,21 @@
-using LightInject;
-using LightInject.Microsoft.DependencyInjection;
-using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Moq;
using NUnit.Framework;
-using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
-using Umbraco.Configuration.Models;
using Umbraco.Core;
using Umbraco.Core.Composing;
-using Umbraco.Core.Composing.LightInject;
-using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
-using Umbraco.Core.Migrations.Install;
-using Umbraco.Core.Persistence;
using Umbraco.Core.Runtime;
using Umbraco.Tests.Common;
+using Umbraco.Tests.Integration.Extensions;
using Umbraco.Tests.Integration.Implementations;
using Umbraco.Tests.Integration.Testing;
using Umbraco.Web.BackOffice.AspNetCore;
-using static Umbraco.Core.Migrations.Install.DatabaseBuilder;
namespace Umbraco.Tests.Integration
{
@@ -39,10 +30,11 @@ namespace Umbraco.Tests.Integration
MyComposer.Reset();
}
- [OneTimeTearDown]
- public void FixtureTearDown()
+ [SetUp]
+ public void Setup()
{
-
+ MyComponent.Reset();
+ MyComposer.Reset();
}
///
@@ -95,7 +87,7 @@ namespace Umbraco.Tests.Integration
[Test]
public async Task AddUmbracoCore()
{
- var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
+ var umbracoContainer = UmbracoIntegrationTest.GetUmbracoContainer(out var serviceProviderFactory);
var testHelper = new TestHelper();
var hostBuilder = new HostBuilder()
@@ -103,7 +95,7 @@ namespace Umbraco.Tests.Integration
.ConfigureServices((hostContext, services) =>
{
var webHostEnvironment = testHelper.GetWebHostEnvironment();
- AddRequiredNetCoreServices(services, testHelper, webHostEnvironment);
+ services.AddRequiredNetCoreServices(testHelper, webHostEnvironment);
// Add it!
services.AddUmbracoConfiguration(hostContext.Configuration);
@@ -134,7 +126,7 @@ namespace Umbraco.Tests.Integration
[Test]
public async Task UseUmbracoCore()
{
- var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
+ var umbracoContainer = UmbracoIntegrationTest.GetUmbracoContainer(out var serviceProviderFactory);
var testHelper = new TestHelper();
var hostBuilder = new HostBuilder()
@@ -142,7 +134,7 @@ namespace Umbraco.Tests.Integration
.ConfigureServices((hostContext, services) =>
{
var webHostEnvironment = testHelper.GetWebHostEnvironment();
- AddRequiredNetCoreServices(services, testHelper, webHostEnvironment);
+ services.AddRequiredNetCoreServices(testHelper, webHostEnvironment);
// Add it!
services.AddUmbracoConfiguration(hostContext.Configuration);
@@ -169,56 +161,6 @@ namespace Umbraco.Tests.Integration
Assert.IsTrue(MyComponent.IsTerminated);
}
- [Test]
- public async Task Install_Database()
- {
- var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
- var testHelper = new TestHelper();
-
- var hostBuilder = new HostBuilder()
- .UseUmbraco(serviceProviderFactory)
- .ConfigureServices((hostContext, services) =>
- {
- var webHostEnvironment = testHelper.GetWebHostEnvironment();
- AddRequiredNetCoreServices(services, testHelper, webHostEnvironment);
-
- // Add it!
- services.AddUmbracoConfiguration(hostContext.Configuration);
- services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly);
- });
-
- var host = await hostBuilder.StartAsync();
- var app = new ApplicationBuilder(host.Services);
-
- // This will create a db, install the schema and ensure the app is configured to run
- app.UseTestLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb"));
-
- app.UseUmbracoCore();
-
- var runtimeState = app.ApplicationServices.GetRequiredService();
- Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
- }
-
- internal static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory)
- {
- var container = UmbracoServiceProviderFactory.CreateServiceContainer();
- serviceProviderFactory = new UmbracoServiceProviderFactory(container);
- var umbracoContainer = serviceProviderFactory.GetContainer();
- return umbracoContainer;
- }
-
- ///
- /// These services need to be manually added because they do not get added by the generic host
- ///
- ///
- ///
- ///
- private void AddRequiredNetCoreServices(IServiceCollection services, TestHelper testHelper, IWebHostEnvironment webHostEnvironment)
- {
- services.AddSingleton(x => testHelper.GetHttpContextAccessor());
- // the generic host does add IHostEnvironment but not this one because we are not actually in a web context
- services.AddSingleton(x => webHostEnvironment);
- }
[RuntimeLevel(MinLevel = RuntimeLevel.Install)]
public class MyComposer : IUserComposer
diff --git a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs
index 63b336701c..da2b83bc39 100644
--- a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs
+++ b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs
@@ -17,16 +17,8 @@ namespace Umbraco.Tests.Integration.Testing
///
/// Manages a pool of LocalDb databases for integration testing
///
- internal class LocalDbTestDatabase
+ public class LocalDbTestDatabase
{
- public static LocalDbTestDatabase Get(string filesPath, ILogger logger, IGlobalSettings globalSettings, IUmbracoDatabaseFactory dbFactory)
- {
- var localDb = new LocalDb();
- if (localDb.IsAvailable == false)
- throw new InvalidOperationException("LocalDB is not available.");
- return new LocalDbTestDatabase(logger, globalSettings, localDb, filesPath, dbFactory);
- }
-
public const string InstanceName = "UmbracoTests";
public const string DatabaseName = "UmbracoTests";
@@ -43,7 +35,8 @@ namespace Umbraco.Tests.Integration.Testing
private static DatabasePool _schemaPool;
private DatabasePool _currentPool;
- public LocalDbTestDatabase(ILogger logger, IGlobalSettings globalSettings, LocalDb localDb, string filesPath, IUmbracoDatabaseFactory dbFactory)
+ //It's internal because `Umbraco.Core.Persistence.LocalDb` is internal
+ internal LocalDbTestDatabase(ILogger logger, IGlobalSettings globalSettings, LocalDb localDb, string filesPath, IUmbracoDatabaseFactory dbFactory)
{
_umbracoVersion = new UmbracoVersion();
_logger = logger;
@@ -328,5 +321,6 @@ namespace Umbraco.Tests.Integration.Testing
while (_readyQueue.TryTake(out i)) { }
}
}
+
}
}
diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
new file mode 100644
index 0000000000..90a6e7bdf8
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using NUnit.Framework;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Composing.LightInject;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Scoping;
+using Umbraco.Tests.Integration.Extensions;
+using Umbraco.Tests.Integration.Implementations;
+using Umbraco.Tests.Testing;
+using Umbraco.Web.BackOffice.AspNetCore;
+
+namespace Umbraco.Tests.Integration.Testing
+{
+ ///
+ /// Abstract class for integration tests
+ ///
+ ///
+ /// This will use a Host Builder to boot and install Umbraco ready for use
+ ///
+ [SingleThreaded]
+ [NonParallelizable]
+ public abstract class UmbracoIntegrationTest
+ {
+ public static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory)
+ {
+ var container = UmbracoServiceProviderFactory.CreateServiceContainer();
+ serviceProviderFactory = new UmbracoServiceProviderFactory(container);
+ var umbracoContainer = serviceProviderFactory.GetContainer();
+ return umbracoContainer;
+ }
+
+ ///
+ /// Get or create an instance of
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// There must only be ONE instance shared between all tests in a session
+ ///
+ public static LocalDbTestDatabase GetOrCreate(string filesPath, ILogger logger, IGlobalSettings globalSettings, IUmbracoDatabaseFactory dbFactory)
+ {
+ lock (_dbLocker)
+ {
+ if (_dbInstance != null) return _dbInstance;
+
+ var localDb = new LocalDb();
+ if (localDb.IsAvailable == false)
+ throw new InvalidOperationException("LocalDB is not available.");
+ _dbInstance = new LocalDbTestDatabase(logger, globalSettings, localDb, filesPath, dbFactory);
+ return _dbInstance;
+ }
+ }
+
+ private static readonly object _dbLocker = new object();
+ private static LocalDbTestDatabase _dbInstance;
+
+ private readonly List _testTeardown = new List();
+ private readonly List _fixtureTeardown = new List();
+
+ public void OnTestTearDown(Action tearDown)
+ {
+ _testTeardown.Add(tearDown);
+ }
+
+ public void OnFixtureTearDown(Action tearDown)
+ {
+ _fixtureTeardown.Add(tearDown);
+ }
+
+ [OneTimeTearDown]
+ public void FixtureTearDown()
+ {
+ // call all registered callbacks
+ foreach (var action in _fixtureTeardown)
+ {
+ action();
+ }
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ // call all registered callbacks
+ foreach (var action in _testTeardown)
+ {
+ action();
+ }
+ }
+
+ [SetUp]
+ public async Task Setup()
+ {
+ var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
+ var testHelper = new TestHelper();
+
+ var hostBuilder = new HostBuilder()
+ .UseUmbraco(serviceProviderFactory)
+ .ConfigureServices((hostContext, services) =>
+ {
+ var webHostEnvironment = testHelper.GetWebHostEnvironment();
+ services.AddRequiredNetCoreServices(testHelper, webHostEnvironment);
+
+ // Add it!
+ services.AddUmbracoConfiguration(hostContext.Configuration);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly);
+ });
+
+ var host = await hostBuilder.StartAsync();
+ var app = new ApplicationBuilder(host.Services);
+ Services = app.ApplicationServices;
+
+ // This will create a db, install the schema and ensure the app is configured to run
+ app.UseTestLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb"), this);
+
+ app.UseUmbracoCore();
+ }
+
+ ///
+ /// Returns the DI container
+ ///
+ protected IServiceProvider Services { get; private set; }
+
+ ///
+ /// Returns the
+ ///
+ protected IScopeProvider ScopeProvider => Services.GetRequiredService();
+
+ ///
+ /// Returns the
+ ///
+ protected IScopeAccessor ScopeAccessor => Services.GetRequiredService();
+
+ ///
+ /// Returns the
+ ///
+ protected ILogger Logger => Services.GetRequiredService();
+ }
+}
diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
index fa037fbb50..4609d8a59c 100644
--- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
@@ -252,8 +252,8 @@ namespace Umbraco.Tests.TestHelpers
TestHelper.DbProviderFactoryCreator);
}
- typeFinder = typeFinder ?? new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
- fileSystems = fileSystems ?? new FileSystems(Current.Factory, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings());
+ typeFinder ??= new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ fileSystems ??= new FileSystems(Current.Factory, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings());
var coreDebug = TestHelper.CoreDebugSettings;
var mediaFileSystem = Mock.Of();
var scopeProvider = new ScopeProvider(databaseFactory, fileSystems, coreDebug, mediaFileSystem, logger, typeFinder, NoAppCache.Instance);
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestOptions.cs b/src/Umbraco.Tests/Testing/UmbracoTestOptions.cs
deleted file mode 100644
index da3ffccc55..0000000000
--- a/src/Umbraco.Tests/Testing/UmbracoTestOptions.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-namespace Umbraco.Tests.Testing
-{
- public static class UmbracoTestOptions
- {
- public enum Logger
- {
- // pure mocks
- Mock,
- // Serilog for tests
- Serilog,
- // console logger
- Console
- }
-
- public enum Database
- {
- // no database
- None,
- // new empty database file for the entire feature
- NewEmptyPerFixture,
- // new empty database file per test
- NewEmptyPerTest,
- // new database file with schema for the entire feature
- NewSchemaPerFixture,
- // new database file with schema per test
- NewSchemaPerTest
- }
-
- public enum TypeLoader
- {
- // the default, global type loader for tests
- Default,
- // create one type loader for the feature
- PerFixture,
- // create one type loader for each test
- PerTest
- }
- }
-}
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 06f6a98573..f667b11aa3 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -231,11 +231,8 @@
-
-
-
@@ -267,7 +264,6 @@
-