Publish MusicStore as part of build (#8578)
* Publish MusicStore as part of build * Add a target to publish MusicStore as part of E2E tests * Publishing for x86 causes unit tests in MusicStore to have weird reference issues. Removing these since they are very pretty low value.
This commit is contained in:
parent
bcead68f0c
commit
f3eaa73c1a
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
{
|
||||
public class PublishedApplicationPublisher : ApplicationPublisher
|
||||
{
|
||||
public PublishedApplicationPublisher(string applicationName)
|
||||
: base(applicationName)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<PublishedApplication> Publish(DeploymentParameters deploymentParameters, ILogger logger)
|
||||
{
|
||||
var path = ResolvePublishedApplicationPath(deploymentParameters, logger);
|
||||
|
||||
logger.LogInformation("Using prepublished application from {PublishDir}", path);
|
||||
|
||||
var target = CreateTempDirectory();
|
||||
|
||||
var source = new DirectoryInfo(path);
|
||||
CachingApplicationPublisher.CopyFiles(source, target, logger);
|
||||
return Task.FromResult(new PublishedApplication(target.FullName, logger));
|
||||
}
|
||||
|
||||
protected virtual string ResolvePublishedApplicationPath(DeploymentParameters deploymentParameters, ILogger logger)
|
||||
{
|
||||
var path = deploymentParameters.PublishedApplicationRootPath;
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(DeploymentParameters)}.{nameof(DeploymentParameters.PublishedApplicationRootPath)} not set.");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
throw new DirectoryNotFoundException($"Published application not found at '{path}'.");
|
||||
}
|
||||
|
||||
return deploymentParameters.PublishedApplicationRootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.0.0
|
|||
MinimumVisualStudioVersion = 16.0.0.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicStore", "samples\MusicStore\MusicStore.csproj", "{3CFBED5D-2ED8-49DB-96FB-BDAA748DC5A0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicStore.Test", "test\MusicStore.Test\MusicStore.Test.csproj", "{CA663205-77DE-4E55-B300-85594181B5A9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicStore.E2ETests", "test\MusicStore.E2ETests\MusicStore.E2ETests.csproj", "{72A5F455-121F-4954-BF28-D712C6BE88EA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Antiforgery", "..\Antiforgery\src\Microsoft.AspNetCore.Antiforgery.csproj", "{DECBCA36-8E91-4A46-914D-832ECCE7D3F4}"
|
||||
|
|
@ -167,18 +165,6 @@ Global
|
|||
{3CFBED5D-2ED8-49DB-96FB-BDAA748DC5A0}.Release|x64.Build.0 = Release|x64
|
||||
{3CFBED5D-2ED8-49DB-96FB-BDAA748DC5A0}.Release|x86.ActiveCfg = Release|x86
|
||||
{3CFBED5D-2ED8-49DB-96FB-BDAA748DC5A0}.Release|x86.Build.0 = Release|x86
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CA663205-77DE-4E55-B300-85594181B5A9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{72A5F455-121F-4954-BF28-D712C6BE88EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{72A5F455-121F-4954-BF28-D712C6BE88EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{72A5F455-121F-4954-BF28-D712C6BE88EA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
<DefineConstants>$(DefineConstants);DEMO</DefineConstants>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<InProcessTestSite>true</InProcessTestSite>
|
||||
<EnableSourceLink>false</EnableSourceLink>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -11,9 +11,6 @@
|
|||
<NoWarn>$(NoWarn);NU1605</NoWarn>
|
||||
<!-- https://github.com/aspnet/AspNetCore/issues/6549 -->
|
||||
<BuildHelixPayload>false</BuildHelixPayload>
|
||||
<IsTestProject>false</IsTestProject>
|
||||
<IsReferenceAssemblyProject>false</IsReferenceAssemblyProject>
|
||||
<IsProjectReferenceProvider>false</IsProjectReferenceProvider>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -39,4 +36,44 @@
|
|||
<Reference Include="System.Data.SqlClient" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="_RunPublishAssets" BeforeTargets="AfterBuild" DependsOnTargets="PublishAssets" Condition="'$(SkipTests)' != 'true' OR '$(BuildHelixPayload)' != 'false'" />
|
||||
|
||||
<Target Name="PublishAssets">
|
||||
<ItemGroup>
|
||||
<Architecture Include="x64" />
|
||||
<Architecture Include="x86" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
|
||||
<ApplicationType Include="Portable;Standalone" Architecture="%(Architecture.Identity)" />
|
||||
|
||||
<PublishAsset
|
||||
Include="..\..\samples\MusicStore\MusicStore.csproj"
|
||||
Architecture="%(ApplicationType.Architecture)"
|
||||
ApplicationType="%(ApplicationType.Identity)"
|
||||
PublishDirectory="$(MSBuildThisFileDirectory)$(OutputPath)testassets\%(ApplicationType.Identity)\%(ApplicationType.Architecture)\" />
|
||||
</ItemGroup>
|
||||
|
||||
<MSBuild
|
||||
Projects="$(MSBuildProjectFullPath)"
|
||||
Targets="_PublishAsset"
|
||||
Properties="PublishProject=%(PublishAsset.Identity);Architecture=%(Architecture);ApplicationType=%(ApplicationType);PublishDirectory=%(PublishDirectory)"
|
||||
BuildInParallel="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_PublishAsset">
|
||||
|
||||
<PropertyGroup>
|
||||
<_TargetOsName Condition=" $([MSBuild]::IsOSPlatform('Windows'))">win</_TargetOsName>
|
||||
<_TargetOsName Condition=" $([MSBuild]::IsOSPlatform('OSX'))">osx</_TargetOsName>
|
||||
<_TargetOsName Condition=" $([MSBuild]::IsOSPlatform('Linux'))">linux</_TargetOsName>
|
||||
|
||||
<PublishCommandOptions>PublishDir=$(PublishDirectory);Configuration=$(Configuration);TargetArchitecture=$(Architecture)</PublishCommandOptions>
|
||||
<PublishCommandOptions Condition="'$(ApplicationType)' == 'Standalone'">$(PublishCommandOptions);RuntimeIdentifier=$(_TargetOsName)-$(Architecture)</PublishCommandOptions>
|
||||
|
||||
<!-- Workaround for https://github.com/aspnet/websdk/issues/422 -->
|
||||
<PublishCommandOptions Condition="'$(ApplicationType)' == 'Portable'">$(PublishCommandOptions);UseAppHost=false;</PublishCommandOptions>
|
||||
</PropertyGroup>
|
||||
|
||||
<MSBuild Projects="$(PublishProject)" Targets="Restore;Publish" Properties="$(PublishCommandOptions)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using MusicStore;
|
||||
using Xunit;
|
||||
|
||||
namespace E2ETests
|
||||
|
|
@ -15,7 +18,7 @@ namespace E2ETests
|
|||
public class PublishAndRunTests : LoggedTest
|
||||
{
|
||||
public static TestMatrix TestVariants
|
||||
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.HttpSys)
|
||||
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.HttpSys, ServerType.Kestrel)
|
||||
.WithTfms(Tfm.NetCoreApp30)
|
||||
.WithAllApplicationTypes()
|
||||
.WithAllHostingModels()
|
||||
|
|
@ -31,15 +34,19 @@ namespace E2ETests
|
|||
var logger = loggerFactory.CreateLogger("Publish_And_Run_Tests");
|
||||
var musicStoreDbName = DbUtils.GetUniqueName();
|
||||
|
||||
var publishDirectory = Path.Combine(AppContext.BaseDirectory, "testassets", variant.ApplicationType.ToString(), variant.Architecture.ToString());
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(variant)
|
||||
{
|
||||
ApplicationName = "MusicStore",
|
||||
ApplicationPath = Helpers.GetApplicationPath(),
|
||||
PublishApplicationBeforeDeployment = true,
|
||||
PublishedApplicationRootPath = publishDirectory,
|
||||
PreservePublishedApplicationForDebugging = Helpers.PreservePublishedApplicationForDebugging,
|
||||
UserAdditionalCleanup = parameters =>
|
||||
{
|
||||
DbUtils.DropDatabase(musicStoreDbName, logger);
|
||||
}
|
||||
},
|
||||
ApplicationPublisher = new PublishedApplicationPublisher("MusicStore"),
|
||||
};
|
||||
|
||||
// Override the connection strings using environment based configuration
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
|
||||
namespace MusicStore
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||
public class PublishAssetAttribute : Attribute
|
||||
{
|
||||
public PublishAssetAttribute(string architecture, string applicationType, string server, string hostingModel, string publishDirectory)
|
||||
{
|
||||
RuntimeArchitecture = Enum.Parse<RuntimeArchitecture>(architecture);
|
||||
ApplicationType = Enum.Parse<ApplicationType>(applicationType);
|
||||
ServerType = Enum.Parse<ServerType>(server);
|
||||
HostingModel = Enum.Parse<HostingModel>(hostingModel);
|
||||
PublishDirectory = publishDirectory;
|
||||
}
|
||||
|
||||
internal TestVariant GetTestVariant()
|
||||
{
|
||||
return new TestVariant
|
||||
{
|
||||
ApplicationType = ApplicationType,
|
||||
Architecture = RuntimeArchitecture,
|
||||
HostingModel = HostingModel,
|
||||
Server = ServerType,
|
||||
Tfm = Tfm.NetCoreApp30,
|
||||
};
|
||||
}
|
||||
|
||||
public RuntimeArchitecture RuntimeArchitecture { get; }
|
||||
|
||||
public ApplicationType ApplicationType { get; }
|
||||
|
||||
public ServerType ServerType { get; }
|
||||
|
||||
public HostingModel HostingModel { get; }
|
||||
|
||||
public string PublishDirectory { get; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MusicStore.Controllers;
|
||||
using MusicStore.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Components
|
||||
{
|
||||
public class CartSummaryComponentTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public CartSummaryComponentTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CartSummaryComponent_Returns_CartedItems()
|
||||
{
|
||||
// Arrange
|
||||
var viewContext = new ViewContext()
|
||||
{
|
||||
HttpContext = new DefaultHttpContext()
|
||||
};
|
||||
|
||||
// Session initialization
|
||||
var cartId = "CartId_A";
|
||||
viewContext.HttpContext.Session = new TestSession();
|
||||
viewContext.HttpContext.Session.SetString("Session", cartId);
|
||||
|
||||
// DbContext initialization
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
PopulateData(dbContext, cartId, albumTitle: "AlbumA", itemCount: 10);
|
||||
|
||||
// CartSummaryComponent initialization
|
||||
var cartSummaryComponent = new CartSummaryComponent(dbContext)
|
||||
{
|
||||
ViewComponentContext = new ViewComponentContext() { ViewContext = viewContext }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await cartSummaryComponent.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
var viewResult = Assert.IsType<ViewViewComponentResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
Assert.Null(viewResult.ViewData.Model);
|
||||
Assert.Equal(10, cartSummaryComponent.ViewBag.CartCount);
|
||||
Assert.Equal("AlbumA", cartSummaryComponent.ViewBag.CartSummary);
|
||||
}
|
||||
|
||||
private static void PopulateData(MusicStoreContext context, string cartId, string albumTitle, int itemCount)
|
||||
{
|
||||
var album = new Album()
|
||||
{
|
||||
AlbumId = 1,
|
||||
Title = albumTitle,
|
||||
};
|
||||
|
||||
var cartItems = Enumerable.Range(1, itemCount).Select(n =>
|
||||
new CartItem()
|
||||
{
|
||||
AlbumId = 1,
|
||||
Album = album,
|
||||
Count = 1,
|
||||
CartId = cartId,
|
||||
}).ToArray();
|
||||
|
||||
context.AddRange(cartItems);
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,254 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using MusicStore.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class CheckoutControllerTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public CheckoutControllerTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddressAndPayment_ReturnsDefaultView()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
|
||||
// Act
|
||||
var result = controller.AddressAndPayment();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddressAndPayment_RedirectToCompleteWhenSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var orderId = 10;
|
||||
var order = new Order()
|
||||
{
|
||||
OrderId = orderId,
|
||||
};
|
||||
|
||||
// Session initialization
|
||||
var cartId = "CartId_A";
|
||||
httpContext.Session = new TestSession();
|
||||
httpContext.Session.SetString("Session", cartId);
|
||||
|
||||
// FormCollection initialization
|
||||
httpContext.Request.Form =
|
||||
new FormCollection(
|
||||
new Dictionary<string, StringValues>()
|
||||
{ { "PromoCode", new[] { "FREE" } } }
|
||||
);
|
||||
|
||||
// UserName initialization
|
||||
var claims = new List<Claim> { new Claim(ClaimTypes.Name, "TestUserName") };
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims));
|
||||
|
||||
// DbContext initialization
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var cartItems = CreateTestCartItems(
|
||||
cartId,
|
||||
itemPrice: 10,
|
||||
numberOfItem: 1);
|
||||
dbContext.AddRange(cartItems.Select(n => n.Album).Distinct());
|
||||
dbContext.AddRange(cartItems);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.AddressAndPayment(dbContext, order, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var redirectResult = Assert.IsType<RedirectToActionResult>(result);
|
||||
Assert.Equal("Complete", redirectResult.ActionName);
|
||||
Assert.Null(redirectResult.ControllerName);
|
||||
Assert.NotNull(redirectResult.RouteValues);
|
||||
|
||||
Assert.Equal(orderId, redirectResult.RouteValues["Id"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddressAndPayment_ReturnsOrderIfInvalidPromoCode()
|
||||
{
|
||||
// Arrange
|
||||
var context = new DefaultHttpContext();
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
|
||||
// AddressAndPayment action reads the Promo code from FormCollection.
|
||||
context.Request.Form =
|
||||
new FormCollection(new Dictionary<string, StringValues>());
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = context;
|
||||
|
||||
// Do not need actual data for Order; the Order object will be checked for the reference equality.
|
||||
var order = new Order();
|
||||
|
||||
// Act
|
||||
var result = await controller.AddressAndPayment(dbContext, order, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Same(order, viewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddressAndPayment_ReturnsOrderIfRequestCanceled()
|
||||
{
|
||||
// Arrange
|
||||
var context = new DefaultHttpContext();
|
||||
context.Request.Form =
|
||||
new FormCollection(new Dictionary<string, StringValues>());
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = context;
|
||||
|
||||
var order = new Order();
|
||||
|
||||
// Act
|
||||
var result = await controller.AddressAndPayment(dbContext, order, new CancellationToken(true));
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Same(order, viewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddressAndPayment_ReturnsOrderIfInvalidOrderModel()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ModelState.AddModelError("a", "ModelErrorA");
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
|
||||
var order = new Order();
|
||||
|
||||
// Act
|
||||
var result = await controller.AddressAndPayment(dbContext, order, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Same(order, viewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Complete_ReturnsOrderIdIfValid()
|
||||
{
|
||||
// Arrange
|
||||
var orderId = 100;
|
||||
var userName = "TestUserA";
|
||||
var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) };
|
||||
|
||||
var httpContext = new DefaultHttpContext()
|
||||
{
|
||||
User = new ClaimsPrincipal(new ClaimsIdentity(claims)),
|
||||
};
|
||||
|
||||
var dbContext =
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
dbContext.Add(new Order()
|
||||
{
|
||||
OrderId = orderId,
|
||||
Username = userName
|
||||
});
|
||||
dbContext.SaveChanges();
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.Complete(dbContext, orderId);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Equal(orderId, viewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Complete_ReturnsErrorIfInvalidOrder()
|
||||
{
|
||||
// Arrange
|
||||
var invalidOrderId = 100;
|
||||
var dbContext =
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = new DefaultHttpContext();
|
||||
|
||||
// Act
|
||||
var result = await controller.Complete(dbContext, invalidOrderId);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
|
||||
Assert.Equal("Error", viewResult.ViewName);
|
||||
}
|
||||
|
||||
private static CartItem[] CreateTestCartItems(string cartId, decimal itemPrice, int numberOfItem)
|
||||
{
|
||||
var albums = Enumerable.Range(1, 10).Select(n =>
|
||||
new Album()
|
||||
{
|
||||
AlbumId = n,
|
||||
Price = itemPrice,
|
||||
}).ToArray();
|
||||
|
||||
var cartItems = Enumerable.Range(1, numberOfItem).Select(n =>
|
||||
new CartItem()
|
||||
{
|
||||
Count = 1,
|
||||
CartId = cartId,
|
||||
AlbumId = n % 10,
|
||||
Album = albums[n % 10],
|
||||
}).ToArray();
|
||||
|
||||
return cartItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MusicStore.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Components
|
||||
{
|
||||
public class GenreMenuComponentTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public GenreMenuComponentTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GenreMenuComponent_Returns_NineGenres()
|
||||
{
|
||||
// Arrange
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var genreMenuComponent = new GenreMenuComponent(dbContext);
|
||||
|
||||
PopulateData(dbContext);
|
||||
|
||||
// Act
|
||||
var result = await genreMenuComponent.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
var viewResult = Assert.IsType<ViewViewComponentResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
var genreResult = Assert.IsType<List<string>>(viewResult.ViewData.Model);
|
||||
Assert.Equal(9, genreResult.Count);
|
||||
}
|
||||
|
||||
private static void PopulateData(MusicStoreContext context)
|
||||
{
|
||||
var genres = Enumerable.Range(1, 10).Select(n => new Genre { GenreId = n });
|
||||
|
||||
context.AddRange(genres);
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MusicStore.Models;
|
||||
using MusicStore.Test;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class HomeControllerTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public HomeControllerTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Error_ReturnsErrorView()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new HomeController(new TestAppSettings());
|
||||
var errorView = "~/Views/Shared/Error.cshtml";
|
||||
|
||||
// Act
|
||||
var result = controller.Error();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
|
||||
Assert.Equal(errorView, viewResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_GetsSixTopAlbums()
|
||||
{
|
||||
// Arrange
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
|
||||
var controller = new HomeController(new TestAppSettings());
|
||||
PopulateData(dbContext);
|
||||
|
||||
// Action
|
||||
var result = await controller.Index(dbContext, cache);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.NotNull(viewResult.ViewData.Model);
|
||||
|
||||
var albums = Assert.IsType<List<Album>>(viewResult.ViewData.Model);
|
||||
Assert.Equal(6, albums.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StatusCodePage_ReturnsStatusCodePage()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new HomeController(new TestAppSettings());
|
||||
var statusCodeView = "~/Views/Shared/StatusCodePage.cshtml";
|
||||
|
||||
// Action
|
||||
var result = controller.StatusCodePage();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
|
||||
Assert.Equal(statusCodeView, viewResult.ViewName);
|
||||
}
|
||||
|
||||
private void PopulateData(DbContext context)
|
||||
{
|
||||
var albums = TestAlbumDataProvider.GetAlbums();
|
||||
|
||||
foreach (var album in albums)
|
||||
{
|
||||
context.Add(album);
|
||||
}
|
||||
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
private class TestAlbumDataProvider
|
||||
{
|
||||
public static Album[] GetAlbums()
|
||||
{
|
||||
var generes = Enumerable.Range(1, 10).Select(n =>
|
||||
new Genre()
|
||||
{
|
||||
GenreId = n,
|
||||
Name = "Genre Name " + n,
|
||||
}).ToArray();
|
||||
|
||||
var artists = Enumerable.Range(1, 10).Select(n =>
|
||||
new Artist()
|
||||
{
|
||||
ArtistId = n + 1,
|
||||
Name = "Artist Name " + n,
|
||||
}).ToArray();
|
||||
|
||||
var albums = Enumerable.Range(1, 10).Select(n =>
|
||||
new Album()
|
||||
{
|
||||
Artist = artists[n - 1],
|
||||
ArtistId = n,
|
||||
Genre = generes[n - 1],
|
||||
GenreId = n,
|
||||
}).ToArray();
|
||||
|
||||
return albums;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MusicStore.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class ManageControllerTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ManageControllerTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddOptions();
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<MusicStoreContext>();
|
||||
|
||||
services.AddMvc();
|
||||
services.AddSingleton<IAuthenticationService, NoOpAuth>();
|
||||
services.AddLogging();
|
||||
|
||||
// IHttpContextAccessor is required for SignInManager, and UserManager
|
||||
var context = new DefaultHttpContext();
|
||||
services.AddSingleton<IHttpContextAccessor>(
|
||||
new HttpContextAccessor()
|
||||
{
|
||||
HttpContext = context,
|
||||
});
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_ReturnsViewBagMessagesExpected()
|
||||
{
|
||||
// Arrange
|
||||
var userId = "TestUserA";
|
||||
var phone = "abcdefg";
|
||||
var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, userId) };
|
||||
|
||||
var userManager = _serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var userManagerResult = await userManager.CreateAsync(
|
||||
new ApplicationUser { Id = userId, UserName = "Test", TwoFactorEnabled = true, PhoneNumber = phone },
|
||||
"Pass@word1");
|
||||
Assert.True(userManagerResult.Succeeded);
|
||||
|
||||
var signInManager = _serviceProvider.GetRequiredService<SignInManager<ApplicationUser>>();
|
||||
|
||||
var httpContext = _serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims));
|
||||
httpContext.RequestServices = _serviceProvider;
|
||||
|
||||
var schemeProvider = _serviceProvider.GetRequiredService<IAuthenticationSchemeProvider>();
|
||||
|
||||
var controller = new ManageController(userManager, signInManager, schemeProvider);
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.Index();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.Empty(controller.ViewBag.StatusMessage);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
var model = Assert.IsType<IndexViewModel>(viewResult.ViewData.Model);
|
||||
Assert.True(model.TwoFactor);
|
||||
Assert.Equal(phone, model.PhoneNumber);
|
||||
Assert.True(model.HasPassword);
|
||||
}
|
||||
|
||||
public class NoOpAuth : IAuthenticationService
|
||||
{
|
||||
public Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.NoResult());
|
||||
}
|
||||
|
||||
public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties)
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties)
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// See License.txt in the project root for license information
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MusicStore.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Test
|
||||
{
|
||||
public class ShoppingCartTest : IClassFixture<ShoppingCartFixture>
|
||||
{
|
||||
private readonly ShoppingCartFixture _fixture;
|
||||
|
||||
public ShoppingCartTest(ShoppingCartFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ComputesTotal()
|
||||
{
|
||||
var cartId = Guid.NewGuid().ToString();
|
||||
using (var db = _fixture.CreateContext())
|
||||
{
|
||||
var a = db.Albums.Add(
|
||||
new Album
|
||||
{
|
||||
Price = 15.99m
|
||||
}).Entity;
|
||||
|
||||
db.CartItems.Add(new CartItem { Album = a, Count = 2, CartId = cartId });
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
Assert.Equal(31.98m, await ShoppingCart.GetCart(db, cartId).GetTotal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ShoppingCartFixture
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ShoppingCartFixture()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public virtual MusicStoreContext CreateContext()
|
||||
=> _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\samples\MusicStore\MusicStore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.Authentication.Core" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Testing" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using MusicStore.Models;
|
||||
using MusicStore.ViewModels;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class ShoppingCartControllerTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ShoppingCartControllerTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
services.AddMvc();
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_ReturnsNoCartItems_WhenSessionEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Session = new TestSession();
|
||||
|
||||
var controller = new ShoppingCartController(
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.Index();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
var model = Assert.IsType<ShoppingCartViewModel>(viewResult.ViewData.Model);
|
||||
Assert.Empty(model.CartItems);
|
||||
Assert.Equal(0, model.CartTotal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_ReturnsNoCartItems_WhenNoItemsInCart()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Session = new TestSession();
|
||||
httpContext.Session.SetString("Session", "CartId_A");
|
||||
|
||||
var controller = new ShoppingCartController(
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.Index();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
var model = Assert.IsType<ShoppingCartViewModel>(viewResult.ViewData.Model);
|
||||
Assert.Empty(model.CartItems);
|
||||
Assert.Equal(0, model.CartTotal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_ReturnsCartItems_WhenItemsInCart()
|
||||
{
|
||||
// Arrange
|
||||
var cartId = "CartId_A";
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Session = new TestSession();
|
||||
httpContext.Session.SetString("Session", cartId);
|
||||
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var cartItems = CreateTestCartItems(
|
||||
cartId,
|
||||
itemPrice: 10,
|
||||
numberOfItem: 5);
|
||||
dbContext.AddRange(cartItems.Select(n => n.Album).Distinct());
|
||||
dbContext.AddRange(cartItems);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
var controller = new ShoppingCartController(
|
||||
dbContext,
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.Index();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
var model = Assert.IsType<ShoppingCartViewModel>(viewResult.ViewData.Model);
|
||||
Assert.Equal(5, model.CartItems.Count);
|
||||
Assert.Equal(5 * 10, model.CartTotal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddToCart_AddsItemToCart()
|
||||
{
|
||||
// Arrange
|
||||
var albumId = 3;
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Session = new TestSession();
|
||||
httpContext.Session.SetString("Session", "CartId_A");
|
||||
|
||||
// Creates the albums of AlbumId = 1 ~ 10.
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var albums = CreateTestAlbums(itemPrice: 10);
|
||||
dbContext.AddRange(albums);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
var controller = new ShoppingCartController(
|
||||
dbContext,
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.AddToCart(albumId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var cart = ShoppingCart.GetCart(dbContext, httpContext);
|
||||
Assert.Single(await cart.GetCartItems());
|
||||
Assert.Equal(albumId, (await cart.GetCartItems()).Single().AlbumId);
|
||||
|
||||
var redirectResult = Assert.IsType<RedirectToActionResult>(result);
|
||||
Assert.Null(redirectResult.ControllerName);
|
||||
Assert.Equal("Index", redirectResult.ActionName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveFromCart_RemovesItemFromCart()
|
||||
{
|
||||
// Arrange
|
||||
var cartId = "CartId_A";
|
||||
var cartItemId = 3;
|
||||
var numberOfItem = 5;
|
||||
var unitPrice = 10;
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
// Session and cart initialization
|
||||
httpContext.Session = new TestSession();
|
||||
httpContext.Session.SetString("Session", cartId);
|
||||
|
||||
// DbContext initialization
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var cartItems = CreateTestCartItems(cartId, unitPrice, numberOfItem);
|
||||
dbContext.AddRange(cartItems.Select(n => n.Album).Distinct());
|
||||
dbContext.AddRange(cartItems);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
// ServiceProvder initialization
|
||||
var serviceProviderFeature = new ServiceProvidersFeature();
|
||||
httpContext.Features.Set<IServiceProvidersFeature>(serviceProviderFeature);
|
||||
|
||||
// AntiForgery initialization
|
||||
serviceProviderFeature.RequestServices = _serviceProvider;
|
||||
var antiForgery = serviceProviderFeature.RequestServices.GetRequiredService<IAntiforgery>();
|
||||
var tokens = antiForgery.GetTokens(httpContext);
|
||||
|
||||
// Header initialization for AntiForgery
|
||||
var headers = new KeyValuePair<string, StringValues>(
|
||||
"RequestVerificationToken",
|
||||
new string[] { tokens.CookieToken + ":" + tokens.RequestToken });
|
||||
httpContext.Request.Headers.Add(headers);
|
||||
|
||||
// Cotroller initialization
|
||||
var controller = new ShoppingCartController(
|
||||
dbContext,
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
var result = await controller.RemoveFromCart(cartItemId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var jsonResult = Assert.IsType<JsonResult>(result);
|
||||
var viewModel = Assert.IsType<ShoppingCartRemoveViewModel>(jsonResult.Value);
|
||||
Assert.Equal(numberOfItem - 1, viewModel.CartCount);
|
||||
Assert.Equal((numberOfItem - 1) * 10, viewModel.CartTotal);
|
||||
Assert.Equal(" has been removed from your shopping cart.", viewModel.Message);
|
||||
|
||||
var cart = ShoppingCart.GetCart(dbContext, httpContext);
|
||||
Assert.DoesNotContain((await cart.GetCartItems()), c => c.CartItemId == cartItemId);
|
||||
}
|
||||
|
||||
private static CartItem[] CreateTestCartItems(string cartId, decimal itemPrice, int numberOfItem)
|
||||
{
|
||||
var albums = CreateTestAlbums(itemPrice);
|
||||
|
||||
var cartItems = Enumerable.Range(1, numberOfItem).Select(n =>
|
||||
new CartItem()
|
||||
{
|
||||
Count = 1,
|
||||
CartId = cartId,
|
||||
AlbumId = n % albums.Length,
|
||||
Album = albums[n % albums.Length],
|
||||
}).ToArray();
|
||||
|
||||
return cartItems;
|
||||
}
|
||||
|
||||
private static Album[] CreateTestAlbums(decimal itemPrice)
|
||||
{
|
||||
return Enumerable.Range(1, 10).Select(n =>
|
||||
new Album()
|
||||
{
|
||||
AlbumId = n,
|
||||
Price = itemPrice,
|
||||
}).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MusicStore.Models;
|
||||
using MusicStore.Test;
|
||||
using Xunit;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class StoreControllerTest
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public StoreControllerTest()
|
||||
{
|
||||
var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddLogging()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_CreatesViewWithGenres()
|
||||
{
|
||||
// Arrange
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
CreateTestGenres(numberOfGenres: 10, numberOfAlbums: 1, dbContext: dbContext);
|
||||
|
||||
var controller = new StoreController(dbContext, new TestAppSettings());
|
||||
|
||||
// Act
|
||||
var result = await controller.Index();
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
var viewModel = Assert.IsType<List<Genre>>(viewResult.ViewData.Model);
|
||||
Assert.Equal(10, viewModel.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Browse_ReturnsHttpNotFoundWhenNoGenreData()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new StoreController(
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||
new TestAppSettings());
|
||||
|
||||
// Act
|
||||
var result = await controller.Browse(string.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<NotFoundResult>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Browse_ReturnsViewWithGenre()
|
||||
{
|
||||
// Arrange
|
||||
var genreName = "Genre 1";
|
||||
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext);
|
||||
|
||||
var controller = new StoreController(dbContext, new TestAppSettings());
|
||||
|
||||
// Act
|
||||
var result = await controller.Browse(genreName);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
var viewModel = Assert.IsType<Genre>(viewResult.ViewData.Model);
|
||||
Assert.Equal(genreName, viewModel.Name);
|
||||
Assert.NotNull(viewModel.Albums);
|
||||
Assert.Equal(3, viewModel.Albums.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Details_ReturnsHttpNotFoundWhenNoAlbumData()
|
||||
{
|
||||
// Arrange
|
||||
var albumId = int.MinValue;
|
||||
var controller = new StoreController(
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||
new TestAppSettings());
|
||||
|
||||
// Act
|
||||
var result = await controller.Details(_serviceProvider.GetRequiredService<IMemoryCache>(), albumId);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<NotFoundResult>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Details_ReturnsAlbumDetail()
|
||||
{
|
||||
// Arrange
|
||||
var albumId = 1;
|
||||
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var genres = CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext);
|
||||
|
||||
var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
|
||||
|
||||
var controller = new StoreController(dbContext, new TestAppSettings());
|
||||
|
||||
// Act
|
||||
var result = await controller.Details(cache, albumId);
|
||||
|
||||
// Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(result);
|
||||
Assert.Null(viewResult.ViewName);
|
||||
|
||||
Assert.NotNull(viewResult.ViewData);
|
||||
var viewModel = Assert.IsType<Album>(viewResult.ViewData.Model);
|
||||
Assert.NotNull(viewModel.Genre);
|
||||
var genre = genres.SingleOrDefault(g => g.GenreId == viewModel.GenreId);
|
||||
Assert.NotNull(genre);
|
||||
Assert.NotNull(genre.Albums.SingleOrDefault(a => a.AlbumId == albumId));
|
||||
Assert.NotNull(viewModel.Artist);
|
||||
Assert.Equal(1, viewModel.ArtistId);
|
||||
|
||||
var cachedAlbum = cache.Get<Album>("album_1");
|
||||
Assert.NotNull(cachedAlbum);
|
||||
Assert.Equal(albumId, cachedAlbum.AlbumId);
|
||||
}
|
||||
|
||||
private static Genre[] CreateTestGenres(int numberOfGenres, int numberOfAlbums, DbContext dbContext)
|
||||
{
|
||||
var artist = new Artist();
|
||||
artist.ArtistId = 1;
|
||||
artist.Name = "Artist1";
|
||||
|
||||
var albums = Enumerable.Range(1, numberOfAlbums * numberOfGenres).Select(n =>
|
||||
new Album()
|
||||
{
|
||||
AlbumId = n,
|
||||
Artist = artist,
|
||||
ArtistId = artist.ArtistId
|
||||
}).ToList();
|
||||
|
||||
var generes = Enumerable.Range(1, numberOfGenres).Select(n =>
|
||||
new Genre()
|
||||
{
|
||||
Albums = albums.Where(i => i.AlbumId % numberOfGenres == n - 1).ToList(),
|
||||
GenreId = n,
|
||||
Name = "Genre " + n
|
||||
});
|
||||
|
||||
var artis = Enumerable.Range(1, numberOfGenres).Select(n =>
|
||||
new Genre()
|
||||
{
|
||||
Albums = albums.Where(i => i.AlbumId % numberOfGenres == n - 1).ToList(),
|
||||
GenreId = n,
|
||||
Name = "Genre " + n,
|
||||
});
|
||||
|
||||
dbContext.Add(artist);
|
||||
dbContext.AddRange(albums);
|
||||
dbContext.AddRange(generes);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
return generes.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace MusicStore.Test
|
||||
{
|
||||
public class TestAppSettings : IOptions<AppSettings>
|
||||
{
|
||||
private readonly AppSettings _appSettings;
|
||||
|
||||
public TestAppSettings(bool storeInCache = true)
|
||||
{
|
||||
_appSettings = new AppSettings()
|
||||
{
|
||||
SiteTitle = "ASP.NET MVC Music Store",
|
||||
CacheDbResults = storeInCache
|
||||
};
|
||||
}
|
||||
|
||||
public AppSettings Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _appSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
internal class TestSession : ISession
|
||||
{
|
||||
private Dictionary<string, byte[]> _store
|
||||
= new Dictionary<string, byte[]>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public IEnumerable<string> Keys { get { return _store.Keys; } }
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
public bool IsAvailable { get; } = true;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_store.Clear();
|
||||
}
|
||||
|
||||
public Task CommitAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task LoadAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
_store.Remove(key);
|
||||
}
|
||||
|
||||
public void Set(string key, byte[] value)
|
||||
{
|
||||
_store[key] = value;
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out byte[] value)
|
||||
{
|
||||
return _store.TryGetValue(key, out value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,16 +11,16 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
public class PublishedApplicationPublisher: ApplicationPublisher
|
||||
public class IISPublishedApplicationPublisher: PublishedApplicationPublisher
|
||||
{
|
||||
private readonly string _applicationName;
|
||||
|
||||
public PublishedApplicationPublisher(string applicationName) : base(applicationName)
|
||||
public IISPublishedApplicationPublisher(string applicationName) : base(applicationName)
|
||||
{
|
||||
_applicationName = applicationName;
|
||||
}
|
||||
|
||||
public override Task<PublishedApplication> Publish(DeploymentParameters deploymentParameters, ILogger logger)
|
||||
protected override string ResolvePublishedApplicationPath(DeploymentParameters deploymentParameters, ILogger logger)
|
||||
{
|
||||
var path = Path.Combine(AppContext.BaseDirectory, GetProfileName(deploymentParameters));
|
||||
|
||||
|
|
@ -31,13 +31,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
path = solutionPath;
|
||||
}
|
||||
|
||||
logger.LogInformation("Using prepublished application from {PublishDir}", path);
|
||||
|
||||
var target = CreateTempDirectory();
|
||||
|
||||
var source = new DirectoryInfo(path);
|
||||
CachingApplicationPublisher.CopyFiles(source, target, logger);
|
||||
return Task.FromResult(new PublishedApplication(target.FullName, logger));
|
||||
return path;
|
||||
}
|
||||
|
||||
private string GetProjectReferencePublishLocation(DeploymentParameters deploymentParameters)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
public class PublishedSitesFixture : IDisposable
|
||||
{
|
||||
public PublishedApplicationPublisher InProcessTestSite { get; } = new PublishedApplicationPublisher(Helpers.GetInProcessTestSitesName());
|
||||
public PublishedApplicationPublisher OutOfProcessTestSite { get; } = new PublishedApplicationPublisher(Helpers.GetOutOfProcessTestSitesName());
|
||||
public PublishedApplicationPublisher InProcessTestSite { get; } = new IISPublishedApplicationPublisher(Helpers.GetInProcessTestSitesName());
|
||||
public PublishedApplicationPublisher OutOfProcessTestSite { get; } = new IISPublishedApplicationPublisher(Helpers.GetOutOfProcessTestSitesName());
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
private static void Configure(IISDeploymentParameters deploymentParameters)
|
||||
{
|
||||
deploymentParameters.ApplicationPublisher = new PublishedApplicationPublisher(Helpers.GetOutOfProcessTestSitesName());;
|
||||
deploymentParameters.ApplicationPublisher = new IISPublishedApplicationPublisher(Helpers.GetOutOfProcessTestSitesName());;
|
||||
deploymentParameters.HostingModel = HostingModel.OutOfProcess;
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
private static void Configure(IISDeploymentParameters deploymentParameters)
|
||||
{
|
||||
deploymentParameters.ApplicationPublisher = new PublishedApplicationPublisher(Helpers.GetOutOfProcessTestSitesName());;
|
||||
deploymentParameters.ApplicationPublisher = new IISPublishedApplicationPublisher(Helpers.GetOutOfProcessTestSitesName());;
|
||||
deploymentParameters.ApplicationPath = Helpers.GetOutOfProcessTestSitesName();
|
||||
deploymentParameters.HostingModel = HostingModel.OutOfProcess;
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
TargetFramework = Tfm.NetCoreApp30,
|
||||
HostingModel = HostingModel.InProcess,
|
||||
PublishApplicationBeforeDeployment = true,
|
||||
ApplicationPublisher = new PublishedApplicationPublisher(Helpers.GetInProcessTestSitesName()),
|
||||
ApplicationPublisher = new IISPublishedApplicationPublisher(Helpers.GetInProcessTestSitesName()),
|
||||
ServerType = DeployerSelector.ServerType
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue