Adding Tests and Refactoring
Functional Tests for RazorPages added
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
using ApplicationCore.Interfaces;
|
using ApplicationCore.Interfaces;
|
||||||
|
using Ardalis.GuardClauses;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ApplicationCore.Entities.BuyerAggregate
|
namespace ApplicationCore.Entities.BuyerAggregate
|
||||||
{
|
{
|
||||||
@@ -14,13 +13,15 @@ namespace ApplicationCore.Entities.BuyerAggregate
|
|||||||
|
|
||||||
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly();
|
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly();
|
||||||
|
|
||||||
protected Buyer()
|
private Buyer()
|
||||||
{
|
{
|
||||||
|
// required by EF
|
||||||
}
|
}
|
||||||
|
|
||||||
public Buyer(string identity) : this()
|
public Buyer(string identity) : this()
|
||||||
{
|
{
|
||||||
IdentityGuid = !string.IsNullOrWhiteSpace(identity) ? identity : throw new ArgumentNullException(nameof(identity));
|
Guard.Against.NullOrEmpty(identity, nameof(identity));
|
||||||
|
IdentityGuid = identity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace ApplicationCore.Entities.OrderAggregate
|
namespace ApplicationCore.Entities.OrderAggregate
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,21 +1,29 @@
|
|||||||
namespace ApplicationCore.Entities.OrderAggregate
|
using Ardalis.GuardClauses;
|
||||||
|
|
||||||
|
namespace ApplicationCore.Entities.OrderAggregate
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the item that was ordered. If catalog item details change, details of
|
/// Represents a snapshot of the item that was ordered. If catalog item details change, details of
|
||||||
/// the item that was part of a completed order should not change.
|
/// the item that was part of a completed order should not change.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CatalogItemOrdered // ValueObject
|
public class CatalogItemOrdered // ValueObject
|
||||||
{
|
{
|
||||||
public CatalogItemOrdered(int catalogItemId, string productName, string pictureUri)
|
public CatalogItemOrdered(int catalogItemId, string productName, string pictureUri)
|
||||||
{
|
{
|
||||||
|
Guard.Against.OutOfRange(catalogItemId, nameof(catalogItemId), 1, int.MaxValue);
|
||||||
|
Guard.Against.NullOrEmpty(productName, nameof(productName));
|
||||||
|
Guard.Against.NullOrEmpty(pictureUri, nameof(pictureUri));
|
||||||
|
|
||||||
CatalogItemId = catalogItemId;
|
CatalogItemId = catalogItemId;
|
||||||
ProductName = productName;
|
ProductName = productName;
|
||||||
PictureUri = pictureUri;
|
PictureUri = pictureUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CatalogItemOrdered()
|
private CatalogItemOrdered()
|
||||||
{
|
{
|
||||||
// required by EF
|
// required by EF
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CatalogItemId { get; private set; }
|
public int CatalogItemId { get; private set; }
|
||||||
public string ProductName { get; private set; }
|
public string ProductName { get; private set; }
|
||||||
public string PictureUri { get; private set; }
|
public string PictureUri { get; private set; }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using ApplicationCore.Interfaces;
|
using ApplicationCore.Interfaces;
|
||||||
|
using Ardalis.GuardClauses;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -9,13 +10,18 @@ namespace ApplicationCore.Entities.OrderAggregate
|
|||||||
{
|
{
|
||||||
private Order()
|
private Order()
|
||||||
{
|
{
|
||||||
|
// required by EF
|
||||||
}
|
}
|
||||||
|
|
||||||
public Order(string buyerId, Address shipToAddress, List<OrderItem> items)
|
public Order(string buyerId, Address shipToAddress, List<OrderItem> items)
|
||||||
{
|
{
|
||||||
|
Guard.Against.NullOrEmpty(buyerId, nameof(buyerId));
|
||||||
|
Guard.Against.Null(shipToAddress, nameof(shipToAddress));
|
||||||
|
Guard.Against.Null(items, nameof(items));
|
||||||
|
|
||||||
|
BuyerId = buyerId;
|
||||||
ShipToAddress = shipToAddress;
|
ShipToAddress = shipToAddress;
|
||||||
_orderItems = items;
|
_orderItems = items;
|
||||||
BuyerId = buyerId;
|
|
||||||
}
|
}
|
||||||
public string BuyerId { get; private set; }
|
public string BuyerId { get; private set; }
|
||||||
|
|
||||||
@@ -43,6 +49,5 @@ namespace ApplicationCore.Entities.OrderAggregate
|
|||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ namespace ApplicationCore.Entities.OrderAggregate
|
|||||||
public decimal UnitPrice { get; private set; }
|
public decimal UnitPrice { get; private set; }
|
||||||
public int Units { get; private set; }
|
public int Units { get; private set; }
|
||||||
|
|
||||||
protected OrderItem()
|
private OrderItem()
|
||||||
{
|
{
|
||||||
|
// required by EF
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrderItem(CatalogItemOrdered itemOrdered, decimal unitPrice, int units)
|
public OrderItem(CatalogItemOrdered itemOrdered, decimal unitPrice, int units)
|
||||||
{
|
{
|
||||||
ItemOrdered = itemOrdered;
|
ItemOrdered = itemOrdered;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ApplicationCore.Exceptions;
|
using ApplicationCore.Exceptions;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
|
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
|
||||||
|
|
||||||
namespace Ardalis.GuardClauses
|
namespace Ardalis.GuardClauses
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ApplicationCore.Entities.OrderAggregate;
|
using ApplicationCore.Entities.OrderAggregate;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ApplicationCore.Interfaces
|
namespace ApplicationCore.Interfaces
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Infrastructure.Data
|
|||||||
{
|
{
|
||||||
return _dbContext.Orders
|
return _dbContext.Orders
|
||||||
.Include(o => o.OrderItems)
|
.Include(o => o.OrderItems)
|
||||||
.Include("OrderItems.ItemOrdered")
|
.Include($"{nameof(Order.OrderItems)}.{nameof(OrderItem.ItemOrdered)}")
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ namespace Infrastructure.Data
|
|||||||
{
|
{
|
||||||
return _dbContext.Orders
|
return _dbContext.Orders
|
||||||
.Include(o => o.OrderItems)
|
.Include(o => o.OrderItems)
|
||||||
.Include("OrderItems.ItemOrdered")
|
.Include($"{nameof(Order.OrderItems)}.{nameof(OrderItem.ItemOrdered)}")
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,28 +69,5 @@ namespace Microsoft.eShopWeb.Controllers
|
|||||||
};
|
};
|
||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OrderViewModel GetOrder()
|
|
||||||
{
|
|
||||||
var order = new OrderViewModel()
|
|
||||||
{
|
|
||||||
OrderDate = DateTimeOffset.Now.AddDays(-1),
|
|
||||||
OrderNumber = 12354,
|
|
||||||
Status = "Submitted",
|
|
||||||
Total = 123.45m,
|
|
||||||
ShippingAddress = new Address("123 Main St.", "Kent", "OH", "United States", "44240")
|
|
||||||
};
|
|
||||||
|
|
||||||
order.OrderItems.Add(new OrderItemViewModel()
|
|
||||||
{
|
|
||||||
ProductId = 1,
|
|
||||||
PictureUrl = "",
|
|
||||||
ProductName = "Something",
|
|
||||||
UnitPrice = 5.05m,
|
|
||||||
Units = 2
|
|
||||||
});
|
|
||||||
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,15 @@ namespace Microsoft.eShopWeb
|
|||||||
public void ConfigureDevelopmentServices(IServiceCollection services)
|
public void ConfigureDevelopmentServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
// use in-memory database
|
// use in-memory database
|
||||||
ConfigureTestingServices(services);
|
ConfigureInMemoryDatabases(services);
|
||||||
|
|
||||||
// use real database
|
// use real database
|
||||||
// ConfigureProductionServices(services);
|
// ConfigureProductionServices(services);
|
||||||
|
|
||||||
|
ConfigureServices(services);
|
||||||
}
|
}
|
||||||
public void ConfigureTestingServices(IServiceCollection services)
|
|
||||||
|
private void ConfigureInMemoryDatabases(IServiceCollection services)
|
||||||
{
|
{
|
||||||
// use in-memory database
|
// use in-memory database
|
||||||
services.AddDbContext<CatalogContext>(c =>
|
services.AddDbContext<CatalogContext>(c =>
|
||||||
@@ -46,8 +48,6 @@ namespace Microsoft.eShopWeb
|
|||||||
// Add Identity DbContext
|
// Add Identity DbContext
|
||||||
services.AddDbContext<AppIdentityDbContext>(options =>
|
services.AddDbContext<AppIdentityDbContext>(options =>
|
||||||
options.UseInMemoryDatabase("Identity"));
|
options.UseInMemoryDatabase("Identity"));
|
||||||
|
|
||||||
ConfigureServices(services);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConfigureProductionServices(IServiceCollection services)
|
public void ConfigureProductionServices(IServiceCollection services)
|
||||||
@@ -86,6 +86,10 @@ namespace Microsoft.eShopWeb
|
|||||||
options.ExpireTimeSpan = TimeSpan.FromHours(1);
|
options.ExpireTimeSpan = TimeSpan.FromHours(1);
|
||||||
options.LoginPath = "/Account/Signin";
|
options.LoginPath = "/Account/Signin";
|
||||||
options.LogoutPath = "/Account/Signout";
|
options.LogoutPath = "/Account/Signout";
|
||||||
|
options.Cookie = new CookieBuilder
|
||||||
|
{
|
||||||
|
IsEssential = true // required for auth to work without explicit user consent; adjust to suit your privacy policy
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
|
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" />
|
<ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\WebRazorPages\WebRazorPages.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Web\Web.csproj" />
|
<ProjectReference Include="..\..\src\Web\Web.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
using Microsoft.eShopWeb.ViewModels;
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Microsoft.eShopWeb;
|
||||||
|
using Microsoft.eShopWeb.ViewModels;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace FunctionalTests.Web.Controllers
|
namespace FunctionalTests.Web.Controllers
|
||||||
{
|
{
|
||||||
public class ApiCatalogControllerList : BaseWebTest
|
public class ApiCatalogControllerList : IClassFixture<CustomWebApplicationFactory<Startup>>
|
||||||
{
|
{
|
||||||
|
public ApiCatalogControllerList(CustomWebApplicationFactory<Startup> factory)
|
||||||
|
{
|
||||||
|
Client = factory.CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client { get; }
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ReturnsFirst10CatalogItems()
|
public async Task ReturnsFirst10CatalogItems()
|
||||||
{
|
{
|
||||||
var response = await _client.GetAsync("/api/catalog/list");
|
var response = await Client.GetAsync("/api/catalog/list");
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
var model = JsonConvert.DeserializeObject<CatalogIndexViewModel>(stringResponse);
|
var model = JsonConvert.DeserializeObject<CatalogIndexViewModel>(stringResponse);
|
||||||
@@ -22,7 +32,7 @@ namespace FunctionalTests.Web.Controllers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task ReturnsLast2CatalogItemsGivenPageIndex1()
|
public async Task ReturnsLast2CatalogItemsGivenPageIndex1()
|
||||||
{
|
{
|
||||||
var response = await _client.GetAsync("/api/catalog/list?page=1");
|
var response = await Client.GetAsync("/api/catalog/list?page=1");
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
var model = JsonConvert.DeserializeObject<CatalogIndexViewModel>(stringResponse);
|
var model = JsonConvert.DeserializeObject<CatalogIndexViewModel>(stringResponse);
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.eShopWeb;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.TestHost;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Infrastructure.Data;
|
|
||||||
using Infrastructure.Identity;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace FunctionalTests.Web.Controllers
|
|
||||||
{
|
|
||||||
public abstract class BaseWebTest
|
|
||||||
{
|
|
||||||
protected readonly HttpClient _client;
|
|
||||||
protected string _contentRoot;
|
|
||||||
|
|
||||||
public BaseWebTest()
|
|
||||||
{
|
|
||||||
_client = GetClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HttpClient GetClient()
|
|
||||||
{
|
|
||||||
var startupAssembly = typeof(Startup).GetTypeInfo().Assembly;
|
|
||||||
_contentRoot = GetProjectPath("src", startupAssembly);
|
|
||||||
var builder = new WebHostBuilder()
|
|
||||||
.UseContentRoot(_contentRoot)
|
|
||||||
.UseEnvironment("Testing")
|
|
||||||
.UseStartup<Startup>();
|
|
||||||
|
|
||||||
var server = new TestServer(builder);
|
|
||||||
|
|
||||||
// seed data
|
|
||||||
using (var scope = server.Host.Services.CreateScope())
|
|
||||||
{
|
|
||||||
var services = scope.ServiceProvider;
|
|
||||||
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
|
|
||||||
var catalogContext = services.GetRequiredService<CatalogContext>();
|
|
||||||
CatalogContextSeed.SeedAsync(catalogContext, loggerFactory)
|
|
||||||
.Wait();
|
|
||||||
|
|
||||||
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
|
|
||||||
AppIdentityDbContextSeed.SeedAsync(userManager).Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.CreateClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
protected 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 = 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, "eShopOnWeb.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}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,10 +10,7 @@ namespace FunctionalTests.Web.Controllers
|
|||||||
{
|
{
|
||||||
public CatalogControllerIndex(CustomWebApplicationFactory<Startup> factory)
|
public CatalogControllerIndex(CustomWebApplicationFactory<Startup> factory)
|
||||||
{
|
{
|
||||||
Client = factory.CreateClient(new WebApplicationFactoryClientOptions
|
Client = factory.CreateClient();
|
||||||
{
|
|
||||||
AllowAutoRedirect = false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpClient Client { get; }
|
public HttpClient Client { get; }
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Infrastructure.Identity;
|
||||||
|
|
||||||
namespace FunctionalTests.Web.Controllers
|
namespace FunctionalTests.Web.Controllers
|
||||||
{
|
{
|
||||||
@@ -14,7 +15,6 @@ namespace FunctionalTests.Web.Controllers
|
|||||||
{
|
{
|
||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
builder.UseEnvironment("Testing");
|
|
||||||
builder.ConfigureServices(services =>
|
builder.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
// Create a new service provider.
|
// Create a new service provider.
|
||||||
@@ -30,6 +30,12 @@ namespace FunctionalTests.Web.Controllers
|
|||||||
options.UseInternalServiceProvider(serviceProvider);
|
options.UseInternalServiceProvider(serviceProvider);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddDbContext<AppIdentityDbContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseInMemoryDatabase("Identity");
|
||||||
|
options.UseInternalServiceProvider(serviceProvider);
|
||||||
|
});
|
||||||
|
|
||||||
// Build the service provider.
|
// Build the service provider.
|
||||||
var sp = services.BuildServiceProvider();
|
var sp = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Microsoft.eShopWeb;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FunctionalTests.Web.Controllers
|
||||||
|
{
|
||||||
|
public class OrderIndexOnGet : IClassFixture<CustomWebApplicationFactory<Startup>>
|
||||||
|
{
|
||||||
|
public OrderIndexOnGet(CustomWebApplicationFactory<Startup> factory)
|
||||||
|
{
|
||||||
|
Client = factory.CreateClient(new WebApplicationFactoryClientOptions
|
||||||
|
{
|
||||||
|
AllowAutoRedirect = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReturnsRedirectGivenAnonymousUser()
|
||||||
|
{
|
||||||
|
var response = await Client.GetAsync("/Order/Index");
|
||||||
|
var redirectLocation = response.Headers.Location.OriginalString;
|
||||||
|
|
||||||
|
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||||
|
Assert.Contains("Account/Signin", redirectLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using Infrastructure.Data;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Microsoft.eShopWeb;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Infrastructure.Identity;
|
||||||
|
|
||||||
|
namespace FunctionalTests.WebRazorPages
|
||||||
|
{
|
||||||
|
public class CustomWebRazorPagesApplicationFactory<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 (ApplicationDbContext) using an in-memory
|
||||||
|
// database for testing.
|
||||||
|
services.AddDbContext<CatalogContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseInMemoryDatabase("InMemoryDbForTesting");
|
||||||
|
options.UseInternalServiceProvider(serviceProvider);
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddDbContext<AppIdentityDbContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseInMemoryDatabase("Identity");
|
||||||
|
options.UseInternalServiceProvider(serviceProvider);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build the service provider.
|
||||||
|
var sp = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
// Create a scope to obtain a reference to the database
|
||||||
|
// context (ApplicationDbContext).
|
||||||
|
using (var scope = sp.CreateScope())
|
||||||
|
{
|
||||||
|
var scopedServices = scope.ServiceProvider;
|
||||||
|
var db = scopedServices.GetRequiredService<CatalogContext>();
|
||||||
|
var loggerFactory = scopedServices.GetRequiredService<ILoggerFactory>();
|
||||||
|
|
||||||
|
var logger = scopedServices
|
||||||
|
.GetRequiredService<ILogger<CustomWebRazorPagesApplicationFactory<TStartup>>>();
|
||||||
|
|
||||||
|
// Ensure the database is created.
|
||||||
|
db.Database.EnsureCreated();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Seed the database with test data.
|
||||||
|
CatalogContextSeed.SeedAsync(db, loggerFactory).Wait();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, $"An error occurred seeding the " +
|
||||||
|
"database with test messages. Error: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
tests/FunctionalTests/WebRazorPages/HomePageOnGet.cs
Normal file
29
tests/FunctionalTests/WebRazorPages/HomePageOnGet.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.eShopWeb.RazorPages;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FunctionalTests.WebRazorPages
|
||||||
|
{
|
||||||
|
public class HomePageOnGet : IClassFixture<CustomWebRazorPagesApplicationFactory<Startup>>
|
||||||
|
{
|
||||||
|
public HomePageOnGet(CustomWebRazorPagesApplicationFactory<Startup> factory)
|
||||||
|
{
|
||||||
|
Client = factory.CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReturnsHomePageWithProductListing()
|
||||||
|
{
|
||||||
|
// Arrange & Act
|
||||||
|
var response = await Client.GetAsync("/");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains(".NET Bot Black Sweatshirt", stringResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
tests/FunctionalTests/WebRazorPages/OrderIndexOnGet.cs
Normal file
32
tests/FunctionalTests/WebRazorPages/OrderIndexOnGet.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Microsoft.eShopWeb;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FunctionalTests.WebRazorPages
|
||||||
|
{
|
||||||
|
public class OrderIndexOnGet : IClassFixture<CustomWebRazorPagesApplicationFactory<Startup>>
|
||||||
|
{
|
||||||
|
public OrderIndexOnGet(CustomWebRazorPagesApplicationFactory<Startup> factory)
|
||||||
|
{
|
||||||
|
Client = factory.CreateClient(new WebApplicationFactoryClientOptions
|
||||||
|
{
|
||||||
|
AllowAutoRedirect = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReturnsRedirectGivenAnonymousUser()
|
||||||
|
{
|
||||||
|
var response = await Client.GetAsync("/Order/Index");
|
||||||
|
var redirectLocation = response.Headers.Location.OriginalString;
|
||||||
|
|
||||||
|
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||||
|
Assert.Contains("Account/Signin", redirectLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace UnitTests.ApplicationCore.Entities.BasketTests
|
namespace UnitTests.ApplicationCore.Entities.BasketTests
|
||||||
{
|
{
|
||||||
public class AddItem
|
public class Total
|
||||||
{
|
{
|
||||||
private int _testCatalogItemId = 123;
|
private int _testCatalogItemId = 123;
|
||||||
private decimal _testUnitPrice = 1.23m;
|
private decimal _testUnitPrice = 1.23m;
|
||||||
|
|||||||
41
tests/UnitTests/ApplicationCore/Entities/OrderTests/Total.cs
Normal file
41
tests/UnitTests/ApplicationCore/Entities/OrderTests/Total.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using ApplicationCore.Entities.OrderAggregate;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnitTests.Builders;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace UnitTests.ApplicationCore.Entities.OrderTests
|
||||||
|
{
|
||||||
|
public class Total
|
||||||
|
{
|
||||||
|
private decimal _testUnitPrice = 42m;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsZeroForNewOrder()
|
||||||
|
{
|
||||||
|
var order = new OrderBuilder().WithNoItems();
|
||||||
|
|
||||||
|
Assert.Equal(0, order.Total());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsCorrectGiven1Item()
|
||||||
|
{
|
||||||
|
var builder = new OrderBuilder();
|
||||||
|
var items = new List<OrderItem>
|
||||||
|
{
|
||||||
|
new OrderItem(builder.TestCatalogItemOrdered, _testUnitPrice, 1)
|
||||||
|
};
|
||||||
|
var order = new OrderBuilder().WithItems(items);
|
||||||
|
Assert.Equal(_testUnitPrice, order.Total());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsCorrectGiven3Items()
|
||||||
|
{
|
||||||
|
var builder = new OrderBuilder();
|
||||||
|
var order = builder.WithDefaultValues();
|
||||||
|
|
||||||
|
Assert.Equal(builder.TestUnitPrice * builder.TestUnits, order.Total());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using ApplicationCore.Entities.OrderAggregate;
|
using ApplicationCore.Entities.OrderAggregate;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace UnitTests.Builders
|
namespace UnitTests.Builders
|
||||||
{
|
{
|
||||||
@@ -34,5 +32,17 @@ namespace UnitTests.Builders
|
|||||||
_order = new Order(TestBuyerId, new AddressBuilder().WithDefaultValues(), itemList);
|
_order = new Order(TestBuyerId, new AddressBuilder().WithDefaultValues(), itemList);
|
||||||
return _order;
|
return _order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Order WithNoItems()
|
||||||
|
{
|
||||||
|
_order = new Order(TestBuyerId, new AddressBuilder().WithDefaultValues(), new List<OrderItem>());
|
||||||
|
return _order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Order WithItems(List<OrderItem> items)
|
||||||
|
{
|
||||||
|
_order = new Order(TestBuyerId, new AddressBuilder().WithDefaultValues(), items);
|
||||||
|
return _order;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user