Adding the unit tests for ViewComponents in MusicStore
This commit is contained in:
parent
ff3ffd9348
commit
797f802906
|
|
@ -25,6 +25,13 @@ namespace MusicStore.Components
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Activate]
|
||||||
|
public ISystemClock Clock
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IViewComponentResult> InvokeAsync()
|
public async Task<IViewComponentResult> InvokeAsync()
|
||||||
{
|
{
|
||||||
var latestAlbum = await Cache.GetOrSet("latestAlbum", async context =>
|
var latestAlbum = await Cache.GetOrSet("latestAlbum", async context =>
|
||||||
|
|
@ -36,11 +43,11 @@ namespace MusicStore.Components
|
||||||
return View(latestAlbum);
|
return View(latestAlbum);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<Album> GetLatestAlbum()
|
private async Task<Album> GetLatestAlbum()
|
||||||
{
|
{
|
||||||
var latestAlbum = DbContext.Albums
|
var latestAlbum = await DbContext.Albums
|
||||||
.OrderByDescending(a => a.Created)
|
.OrderByDescending(a => a.Created)
|
||||||
.Where(a => (a.Created - DateTime.UtcNow).TotalDays <= 2)
|
.Where(a => (a.Created - Clock.UtcNow).TotalDays <= 2)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
return latestAlbum;
|
return latestAlbum;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MusicStore.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Abstracts the system clock to facilitate testing.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISystemClock
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a DateTime object that is set to the current date and time on this computer,
|
||||||
|
/// expressed as the Coordinated Universal Time(UTC)
|
||||||
|
/// </summary>
|
||||||
|
DateTime UtcNow { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MusicStore.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to the normal system clock.
|
||||||
|
/// </summary>
|
||||||
|
public class SystemClock : ISystemClock
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public DateTime UtcNow
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// The clock measures whole seconds only, and truncates the milliseconds,
|
||||||
|
// because millisecond resolution is inconsistent among various underlying systems.
|
||||||
|
DateTime utcNow = DateTime.UtcNow;
|
||||||
|
return utcNow.AddMilliseconds(-utcNow.Millisecond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -147,7 +147,7 @@ namespace MusicStore.Models
|
||||||
return order.OrderId;
|
return order.OrderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're using HttpContextBase to allow access to cookies.
|
// We're using HttpContextBase to allow access to sessions.
|
||||||
private string GetCartId(HttpContext context)
|
private string GetCartId(HttpContext context)
|
||||||
{
|
{
|
||||||
var cartId = context.Session.GetString("Session");
|
var cartId = context.Session.GetString("Session");
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Microsoft.Framework.ConfigurationModel;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.Logging;
|
using Microsoft.Framework.Logging;
|
||||||
using Microsoft.Framework.Runtime;
|
using Microsoft.Framework.Runtime;
|
||||||
|
using MusicStore.Components;
|
||||||
using MusicStore.Models;
|
using MusicStore.Models;
|
||||||
|
|
||||||
namespace MusicStore
|
namespace MusicStore
|
||||||
|
|
@ -104,6 +105,9 @@ namespace MusicStore
|
||||||
services.AddCaching();
|
services.AddCaching();
|
||||||
services.AddSession();
|
services.AddSession();
|
||||||
|
|
||||||
|
// Add the system clock service
|
||||||
|
services.AddSingleton<ISystemClock, SystemClock>();
|
||||||
|
|
||||||
// Configure Auth
|
// Configure Auth
|
||||||
services.Configure<AuthorizationOptions>(options =>
|
services.Configure<AuthorizationOptions>(options =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
using System;
|
||||||
|
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.Components
|
||||||
|
{
|
||||||
|
public class AnnouncementComponentTest
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public AnnouncementComponentTest()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services.AddEntityFramework()
|
||||||
|
.AddInMemoryStore()
|
||||||
|
.AddDbContext<MusicStoreContext>();
|
||||||
|
|
||||||
|
_serviceProvider = services.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AnnouncementComponent_Returns_LatestAlbum()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var today = new DateTime(year: 2002, month: 10, day: 30);
|
||||||
|
|
||||||
|
var announcementComponent = new AnnouncementComponent()
|
||||||
|
{
|
||||||
|
DbContext = _serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||||
|
Cache = _serviceProvider.GetRequiredService<IMemoryCache>(),
|
||||||
|
Clock = new TestSystemClock() { UtcNow = today },
|
||||||
|
};
|
||||||
|
|
||||||
|
PopulateData(announcementComponent.DbContext, latestAlbumDate: today);
|
||||||
|
|
||||||
|
// Action
|
||||||
|
var result = await announcementComponent.InvokeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
var viewResult = Assert.IsType<ViewViewComponentResult>(result);
|
||||||
|
Assert.Null(viewResult.ViewName);
|
||||||
|
var albumResult = Assert.IsType<Album>(viewResult.ViewData.Model);
|
||||||
|
Assert.Equal(today, albumResult.Created.Date);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PopulateData(DbContext context, DateTime latestAlbumDate)
|
||||||
|
{
|
||||||
|
var albums = TestAlbumDataProvider.GetAlbums(latestAlbumDate);
|
||||||
|
|
||||||
|
foreach (var album in albums)
|
||||||
|
{
|
||||||
|
context.Add(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestAlbumDataProvider
|
||||||
|
{
|
||||||
|
public static Album[] GetAlbums(DateTime latestAlbumDate)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
Created = latestAlbumDate.AddDays(1 - n),
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
return albums;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestSystemClock : ISystemClock
|
||||||
|
{
|
||||||
|
public DateTime UtcNow { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.AspNet.Session;
|
||||||
|
using Microsoft.Framework.Caching.Distributed;
|
||||||
|
using Microsoft.Framework.Caching.Memory;
|
||||||
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
using Microsoft.Framework.Logging.Testing;
|
||||||
|
using MusicStore.Models;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace MusicStore.Components
|
||||||
|
{
|
||||||
|
public class CartSummaryComponentTest
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public CartSummaryComponentTest()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services.AddEntityFramework()
|
||||||
|
.AddInMemoryStore()
|
||||||
|
.AddDbContext<MusicStoreContext>();
|
||||||
|
|
||||||
|
_serviceProvider = services.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CartSummaryComponent_Returns_CartedItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var viewContext = new ViewContext()
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Session initialization
|
||||||
|
var cartId = "CartId_A";
|
||||||
|
var sessionFeature = new SessionFeature()
|
||||||
|
{
|
||||||
|
Session = CreateTestSession(),
|
||||||
|
};
|
||||||
|
viewContext.HttpContext.SetFeature<ISessionFeature>(sessionFeature);
|
||||||
|
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 = dbContext,
|
||||||
|
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 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 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
using MusicStore.Models;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace MusicStore.Components
|
||||||
|
{
|
||||||
|
public class GenreMenuComponentTest
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public GenreMenuComponentTest()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddEntityFramework()
|
||||||
|
.AddInMemoryStore()
|
||||||
|
.AddDbContext<MusicStoreContext>();
|
||||||
|
|
||||||
|
_serviceProvider = services.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GenreMenuComponent_Returns_NineGenres()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var genreMenuComponent = new GenreMenuComponent()
|
||||||
|
{
|
||||||
|
DbContext = _serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
PopulateData(genreMenuComponent.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<Genre>>(viewResult.ViewData.Model);
|
||||||
|
Assert.Equal(9, genreResult.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PopulateData(MusicStoreContext context)
|
||||||
|
{
|
||||||
|
var genres = Enumerable.Range(1, 10).Select(n => new Genre());
|
||||||
|
|
||||||
|
context.AddRange(genres);
|
||||||
|
context.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue