Unverified Commit d51fca4a authored by Steve Smith's avatar Steve Smith Committed by GitHub

Merge pull request #16 from sdepouw/integration-test-upgrade

Replace BaseWebTest with CustomWebApplicationFactory
parents 88e46889 6dcfc0ab
......@@ -72,15 +72,6 @@ namespace CleanArchitecture.Web
return container.GetInstance<IServiceProvider>();
}
public void ConfigureTesting(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
this.Configure(app, env, loggerFactory);
SeedData.PopulateTestData(app.ApplicationServices.GetService<AppDbContext>());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
......
......@@ -28,6 +28,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Moq" Version="4.8.2" />
......
using CleanArchitecture.Core.Entities;
using CleanArchitecture.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Xunit;
namespace CleanArchitecture.Tests.Integration.Web
{
public class ApiToDoItemsControllerList : BaseWebTest
public class ApiToDoItemsControllerList : IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
public ApiToDoItemsControllerList(CustomWebApplicationFactory<Startup> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task ReturnsTwoItems()
{
......@@ -29,4 +32,4 @@ namespace CleanArchitecture.Tests.Integration.Web
Assert.Equal(1, result.Count(a => a.Title == "Test Item 2"));
}
}
}
\ No newline at end of file
}
using CleanArchitecture.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ViewComponents;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Net.Http;
using System.Reflection;
namespace CleanArchitecture.Tests.Integration.Web
{
public abstract class BaseWebTest
{
protected readonly HttpClient _client;
public BaseWebTest()
{
_client = GetClient();
}
protected HttpClient GetClient()
{
var startupAssembly = typeof(Startup).GetTypeInfo().Assembly;
var contentRoot = GetProjectPath("src", startupAssembly);
var builder = new WebHostBuilder()
.UseContentRoot(contentRoot)
.ConfigureServices(InitializeServices)
.UseStartup<Startup>()
.UseEnvironment("Testing"); // ensure ConfigureTesting is called in Startup
var server = new TestServer(builder);
var client = server.CreateClient();
return client;
}
protected virtual void InitializeServices(IServiceCollection services)
{
var startupAssembly = typeof(Startup).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);
}
/// <summary>
/// Gets the full path to the target project path that we wish to test
/// </summary>
/// <param name="solutionRelativePath">
/// The parent directory of the target project.
/// e.g. src, samples, test, or test/Websites
/// </param>
/// <param name="startupAssembly">The target project's assembly.</param>
/// <returns>The full path to the target project.</returns>
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
// AppContext.BaseDirectory or AppDomain.CurrentDomain.BaseDirectory contain the BaseDirectory.
var applicationBasePath = AppContext.BaseDirectory;
// 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, "CleanArchitecture.sln"));
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}.");
}
}
}
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Infrastructure.Data;
using CleanArchitecture.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace CleanArchitecture.Tests.Integration.Web
{
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Create a new service provider.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Add a database context (AppDbContext) using an in-memory
// database for testing.
services.AddDbContext<AppDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
options.UseInternalServiceProvider(serviceProvider);
});
services.AddScoped<IDomainEventDispatcher, NoOpDomainEventDispatcher>();
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database
// context (AppDbContext).
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<AppDbContext>();
var logger = scopedServices
.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
// Ensure the database is created.
db.Database.EnsureCreated();
try
{
// Seed the database with test data.
SeedData.PopulateTestData(db);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred seeding the " +
"database with test messages. Error: {ex.Message}");
}
}
});
}
}
}
using System.Threading.Tasks;
using CleanArchitecture.Web;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
namespace CleanArchitecture.Tests.Integration.Web
{
public class HomeControllerIndexShould : BaseWebTest
public class HomeControllerIndexShould : IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
public HomeControllerIndexShould(CustomWebApplicationFactory<Startup> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task ReturnViewWithCorrectMessage()
{
var response = await _client.GetAsync("/");
HttpResponseMessage response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
string stringResponse = await response.Content.ReadAsStringAsync();
Assert.Contains("CleanArchitecture.Web", stringResponse);
}
}
}
\ No newline at end of file
}
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Core.SharedKernel;
namespace CleanArchitecture.Tests.Integration.Web
{
public class NoOpDomainEventDispatcher : IDomainEventDispatcher
{
public void Dispatch(BaseDomainEvent domainEvent) { }
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment