From 1b502cbee7b86709a0b9a0afd4de4f3c97db52ae Mon Sep 17 00:00:00 2001 From: ianhong Date: Mon, 9 Mar 2015 11:23:28 -0700 Subject: [PATCH] Music Store sample Unit Tests - (except usermanager and signinmanager) --- .../Controllers/ShoppingCartController.cs | 2 +- .../MusicStore.Test/CheckoutControllerTest.cs | 101 +++++++++- test/MusicStore.Test/ManageControllerTest.cs | 1 - .../ShoppingCartControllerTest.cs | 126 ++++++++++++- test/MusicStore.Test/StoreControllerTest.cs | 175 ++++++++++++++++++ 5 files changed, 393 insertions(+), 12 deletions(-) create mode 100644 test/MusicStore.Test/StoreControllerTest.cs diff --git a/src/MusicStore/Controllers/ShoppingCartController.cs b/src/MusicStore/Controllers/ShoppingCartController.cs index c35a019180..1ff697f262 100644 --- a/src/MusicStore/Controllers/ShoppingCartController.cs +++ b/src/MusicStore/Controllers/ShoppingCartController.cs @@ -58,7 +58,7 @@ namespace MusicStore.Controllers public async Task RemoveFromCart(int id, CancellationToken requestAborted) { var cookieToken = string.Empty; - string formToken = string.Empty; + var formToken = string.Empty; string[] tokenHeaders = null; string[] tokens = null; diff --git a/test/MusicStore.Test/CheckoutControllerTest.cs b/test/MusicStore.Test/CheckoutControllerTest.cs index a2e75dd099..43ec6212a8 100644 --- a/test/MusicStore.Test/CheckoutControllerTest.cs +++ b/test/MusicStore.Test/CheckoutControllerTest.cs @@ -1,17 +1,22 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core.Collections; using Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Routing; +using Microsoft.AspNet.Session; +using Microsoft.AspNet.Testing.Logging; +using Microsoft.Framework.Caching.Distributed; +using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.DependencyInjection; using MusicStore.Models; using Xunit; -namespace MusicStore.Controllers +namespace MusicStore.Controllers { public class CheckoutControllerTest { @@ -42,6 +47,66 @@ namespace MusicStore.Controllers 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"; + var sessionFeature = new SessionFeature() + { + Session = CreateTestSession(), + }; + httpContext.SetFeature(sessionFeature); + httpContext.Session.SetString("Session", cartId); + + // FormCollection initialization + httpContext.Request.Form = + new FormCollection( + new Dictionary() + { { "PromoCode", new string[] { "FREE" } } } + ); + + // UserName initialization + var claims = new List { new Claim(ClaimTypes.Name, "TestUserName") }; + httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims)); + + // DbContext initialization + var dbContext = _serviceProvider.GetRequiredService(); + 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() + { + DbContext = dbContext, + }; + controller.ActionContext.HttpContext = httpContext; + + // Act + var result = await controller.AddressAndPayment(order, CancellationToken.None); + + // Assert + var redirectResult = Assert.IsType(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() { @@ -174,5 +239,37 @@ namespace MusicStore.Controllers Assert.Equal("Error", viewResult.ViewName); } + + private static ISession CreateTestSession() + { + return new DistributedSession( + new LocalCache(new MemoryCache(new MemoryCacheOptions())), + "sessionId_A", + idleTimeout: TimeSpan.MaxValue, + tryEstablishSession: () => true, + loggerFactory: new NullLoggerFactory(), + isNewSessionKey: true); + } + + 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; + } } } \ No newline at end of file diff --git a/test/MusicStore.Test/ManageControllerTest.cs b/test/MusicStore.Test/ManageControllerTest.cs index 6dc7dfea2a..6860696d20 100644 --- a/test/MusicStore.Test/ManageControllerTest.cs +++ b/test/MusicStore.Test/ManageControllerTest.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Authentication; using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core.Authentication; diff --git a/test/MusicStore.Test/ShoppingCartControllerTest.cs b/test/MusicStore.Test/ShoppingCartControllerTest.cs index 48e47501e4..9d27d7b7ca 100644 --- a/test/MusicStore.Test/ShoppingCartControllerTest.cs +++ b/test/MusicStore.Test/ShoppingCartControllerTest.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; @@ -27,6 +29,8 @@ namespace MusicStore.Controllers .AddInMemoryStore() .AddDbContext(); + services.AddMvc(); + _serviceProvider = services.BuildServiceProvider(); } @@ -135,6 +139,107 @@ namespace MusicStore.Controllers Assert.Equal(5 * 10, model.CartTotal); } + [Fact] + public async Task AddToCart_AddsItemToCart() + { + // Arrange + var albumId = 3; + var sessionFeature = new SessionFeature() + { + Session = CreateTestSession(), + }; + + var httpContext = new DefaultHttpContext(); + httpContext.SetFeature(sessionFeature); + httpContext.Session.SetString("Session", "CartId_A"); + + // Creates the albums of AlbumId = 1 ~ 10. + var dbContext = _serviceProvider.GetRequiredService(); + var albums = CreateTestAlbums(itemPrice: 10); + dbContext.AddRange(albums); + dbContext.SaveChanges(); + + var controller = new ShoppingCartController() + { + DbContext = dbContext + }; + controller.ActionContext.HttpContext = httpContext; + + // Act + var result = await controller.AddToCart(albumId, CancellationToken.None); + + // Assert + var cart = ShoppingCart.GetCart(dbContext, httpContext); + Assert.Equal(1, (await cart.GetCartItems()).Count); + Assert.Equal(albumId, (await cart.GetCartItems()).Single().AlbumId); + + var redirectResult = Assert.IsType(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 + var sessionFeature = new SessionFeature() + { + Session = CreateTestSession(), + }; + httpContext.SetFeature(sessionFeature); + httpContext.Session.SetString("Session", cartId); + + // DbContext initialization + var dbContext = _serviceProvider.GetRequiredService(); + 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.SetFeature(serviceProviderFeature); + + // AntiForgery initialization + serviceProviderFeature.RequestServices = _serviceProvider; + var antiForgery = serviceProviderFeature.RequestServices.GetRequiredService(); + var tokens = antiForgery.GetTokens(httpContext, "testToken"); + + // Header initialization for AntiForgery + var headers = new KeyValuePair( + "RequestVerificationToken", + new string[] { tokens.CookieToken + ":" + tokens.FormToken }); + httpContext.Request.Headers.Add(headers); + + // Cotroller initialization + var controller = new ShoppingCartController() + { + DbContext = dbContext, + AntiForgery = antiForgery, + }; + controller.ActionContext.HttpContext = httpContext; + + // Act + var result = await controller.RemoveFromCart(cartItemId, CancellationToken.None); + + // Assert + var jsonResult = Assert.IsType(result); + var viewModel = Assert.IsType(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.False((await cart.GetCartItems()).Any(c => c.CartItemId == cartItemId)); + } + private static ISession CreateTestSession() { @@ -149,23 +254,28 @@ namespace MusicStore.Controllers 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 albums = CreateTestAlbums(itemPrice); var cartItems = Enumerable.Range(1, numberOfItem).Select(n => new CartItem() { Count = 1, CartId = cartId, - AlbumId = n, - Album = albums[n - 1], + 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(); + } } } \ No newline at end of file diff --git a/test/MusicStore.Test/StoreControllerTest.cs b/test/MusicStore.Test/StoreControllerTest.cs new file mode 100644 index 0000000000..ae7892f42f --- /dev/null +++ b/test/MusicStore.Test/StoreControllerTest.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc; +using Microsoft.Data.Entity; +using Microsoft.Framework.Caching.Memory; +using Microsoft.Framework.DependencyInjection; +using MusicStore.Models; +using Xunit; + +namespace MusicStore.Controllers +{ + public class StoreControllerTest + { + private readonly IServiceProvider _serviceProvider; + + public StoreControllerTest() + { + var services = new ServiceCollection(); + + services.AddEntityFramework() + .AddInMemoryStore() + .AddDbContext(); + + _serviceProvider = services.BuildServiceProvider(); + } + + [Fact] + public async Task Index_CreatesViewWithGenres() + { + // Arrange + var dbContext = _serviceProvider.GetRequiredService(); + CreateTestGenres(numberOfGenres: 10, numberOfAlbums: 1, dbContext: dbContext); + + var controller = new StoreController() + { + DbContext = dbContext, + }; + + // Act + var result = await controller.Index(); + + // Assert + var viewResult = Assert.IsType(result); + Assert.Null(viewResult.ViewName); + + Assert.NotNull(viewResult.ViewData); + var viewModel = Assert.IsType>(viewResult.ViewData.Model); + Assert.Equal(10, viewModel.Count); + } + + [Fact] + public async Task Browse_ReturnsHttpNotFoundWhenNoGenreData() + { + // Arrange + var controller = new StoreController() + { + DbContext = _serviceProvider.GetRequiredService(), + }; + + // Act + var result = await controller.Browse(string.Empty); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async Task Browse_ReturnsViewWithGenre() + { + // Arrange + var genreName = "Genre 1"; + + var dbContext = _serviceProvider.GetRequiredService(); + CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext); + + var controller = new StoreController() + { + DbContext = dbContext, + }; + + // Act + var result = await controller.Browse(genreName); + + // Assert + var viewResult = Assert.IsType(result); + Assert.Null(viewResult.ViewName); + + Assert.NotNull(viewResult.ViewData); + var viewModel = Assert.IsType(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() + { + DbContext = _serviceProvider.GetRequiredService(), + Cache = _serviceProvider.GetRequiredService(), + }; + + // Act + var result = await controller.Details(albumId); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async Task Details_ReturnsAlbumDetail() + { + // Arrange + var albumId = 1; + + var dbContext = _serviceProvider.GetRequiredService(); + var genres = CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext); + + var cache = _serviceProvider.GetRequiredService(); + + var controller = new StoreController() + { + DbContext = dbContext, + Cache = cache, + }; + + // Act + var result = await controller.Details(albumId); + + // Assert + var viewResult = Assert.IsType(result); + Assert.Null(viewResult.ViewName); + + Assert.NotNull(viewResult.ViewData); + var viewModel = Assert.IsType(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.Null(viewModel.Artist); + + var cachedAlbum = cache.Get>("album_1"); + Assert.NotNull(cachedAlbum); + Assert.Equal(albumId, cachedAlbum.Result.AlbumId); + } + + private static Genre[] CreateTestGenres(int numberOfGenres, int numberOfAlbums, DbContext dbContext) + { + var albums = Enumerable.Range(1, numberOfAlbums * numberOfGenres).Select(n => + new Album() + { + AlbumId = n, + }).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, + }); + + dbContext.AddRange(albums); + dbContext.AddRange(generes); + dbContext.SaveChanges(); + + return generes.ToArray(); + } + } +} \ No newline at end of file