using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using System; using System.IO; using System.Net.Http; using Microsoft.Extensions.PlatformAbstractions; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.ViewComponents; namespace LanBackup.WebApp.Tests { public class TestFixture : IDisposable { private const string SolutionName = "LanBackup.sln"; private readonly TestServer _server; public HttpClient Client; public TestFixture() : this(Path.Combine("src")) { } protected TestFixture(string solutionRelativeTargetProjectParentDir) { var startupAssembly = typeof(TStartup).GetTypeInfo().Assembly; var contentRoot = GetProjectPath(solutionRelativeTargetProjectParentDir, startupAssembly); var builder = new WebHostBuilder() .UseContentRoot(contentRoot) .ConfigureServices(InitializeServices) .UseEnvironment("Development") .UseStartup(typeof(TStartup)); _server = new TestServer(builder); Client = _server.CreateClient(); } public void Dispose() { Client.Dispose(); _server.Dispose(); } protected virtual void InitializeServices(IServiceCollection services) { var startupAssembly = typeof(TStartup).GetTypeInfo().Assembly; // Inject a custom application part manager. Overrides AddMvcCore() because that uses TryAdd(). var manager = new ApplicationPartManager(); manager.ApplicationParts.Add(new AssemblyPart(startupAssembly)); manager.FeatureProviders.Add(new ControllerFeatureProvider()); manager.FeatureProviders.Add(new ViewComponentFeatureProvider()); services.AddSingleton(manager); } /// /// Gets the full path to the target project path that we wish to test /// /// /// The parent directory of the target project. /// e.g. src, samples, test, or test/Websites /// /// The target project's assembly. /// The full path to the target project. private static string GetProjectPath(string solutionRelativePath, Assembly startupAssembly) { // Get name of the target project which we want to test var projectName = startupAssembly.GetName().Name; // Get currently executing test project path var applicationBasePath = PlatformServices.Default.Application.ApplicationBasePath; // Find the folder which contains the solution file. We then use this information to find the target // project which we want to test. var directoryInfo = new DirectoryInfo(applicationBasePath); do { var solutionFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, SolutionName)); if (solutionFileInfo.Exists) { return Path.GetFullPath(Path.Combine(directoryInfo.FullName, solutionRelativePath, projectName)); } directoryInfo = directoryInfo.Parent; } while (directoryInfo.Parent != null); throw new Exception($"Solution root could not be located using application root {applicationBasePath}."); } } }