Skip to content

Commit

Permalink
Adding guards and more tests (dotnet-architecture#68)
Browse files Browse the repository at this point in the history
* Adding single entity by spec method to repository

* Adding guards and more unit tests
  • Loading branch information
ardalis authored Oct 30, 2017
1 parent 3d46c80 commit b864be9
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/ApplicationCore/ApplicationCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="1.1.1" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
</ItemGroup>

Expand Down
23 changes: 23 additions & 0 deletions src/ApplicationCore/Exceptions/BasketNotFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;

namespace ApplicationCore.Exceptions
{
public class BasketNotFoundException : Exception
{
public BasketNotFoundException(int basketId) : base($"No basket found with id {basketId}")
{
}

protected BasketNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
{
}

public BasketNotFoundException(string message) : base(message)
{
}

public BasketNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
14 changes: 14 additions & 0 deletions src/ApplicationCore/Exceptions/GuardExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using ApplicationCore.Exceptions;
using Microsoft.eShopWeb.ApplicationCore.Entities;

namespace Ardalis.GuardClauses
{
public static class FooGuard
{
public static void NullBasket(this IGuardClause guardClause, int basketId, Basket basket)
{
if (basket == null)
throw new BasketNotFoundException(basketId);
}
}
}
2 changes: 1 addition & 1 deletion src/ApplicationCore/Interfaces/IRepository.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ApplicationCore.Interfaces
{
public interface IRepository<T> where T : BaseEntity
{
T GetById(int id);
T GetSingleBySpec(ISpecification<T> spec);
IEnumerable<T> ListAll();
IEnumerable<T> List(ISpecification<T> spec);
T Add(T entity);
Expand Down
6 changes: 6 additions & 0 deletions src/ApplicationCore/Services/BasketService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using ApplicationCore.Specifications;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Linq;
using Ardalis.GuardClauses;

namespace ApplicationCore.Services
{
Expand Down Expand Up @@ -43,6 +44,7 @@ public async Task DeleteBasketAsync(int basketId)

public async Task<int> GetBasketItemCountAsync(string userName)
{
Guard.Against.NullOrEmpty(userName, nameof(userName));
var basketSpec = new BasketWithItemsSpecification(userName);
var basket = (await _basketRepository.ListAsync(basketSpec)).FirstOrDefault();
if (basket == null)
Expand All @@ -57,7 +59,9 @@ public async Task<int> GetBasketItemCountAsync(string userName)

public async Task SetQuantities(int basketId, Dictionary<string, int> quantities)
{
Guard.Against.Null(quantities, nameof(quantities));
var basket = await _basketRepository.GetByIdAsync(basketId);
Guard.Against.NullBasket(basketId, basket);
foreach (var item in basket.Items)
{
if (quantities.TryGetValue(item.Id.ToString(), out var quantity))
Expand All @@ -71,6 +75,8 @@ public async Task SetQuantities(int basketId, Dictionary<string, int> quantities

public async Task TransferBasketAsync(string anonymousId, string userName)
{
Guard.Against.NullOrEmpty(anonymousId, nameof(anonymousId));
Guard.Against.NullOrEmpty(userName, nameof(userName));
var basketSpec = new BasketWithItemsSpecification(anonymousId);
var basket = (await _basketRepository.ListAsync(basketSpec)).FirstOrDefault();
if (basket == null) return;
Expand Down
2 changes: 2 additions & 0 deletions src/ApplicationCore/Services/OrderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Collections.Generic;
using Ardalis.GuardClauses;

namespace ApplicationCore.Services
{
Expand All @@ -24,6 +25,7 @@ public OrderService(IAsyncRepository<Basket> basketRepository,
public async Task CreateOrderAsync(int basketId, Address shippingAddress)
{
var basket = await _basketRepository.GetByIdAsync(basketId);
Guard.Against.NullBasket(basketId, basket);
var items = new List<OrderItem>();
foreach (var item in basket.Items)
{
Expand Down
6 changes: 6 additions & 0 deletions src/Infrastructure/Data/EfRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public virtual T GetById(int id)
return _dbContext.Set<T>().Find(id);
}

public T GetSingleBySpec(ISpecification<T> spec)
{
return List(spec).FirstOrDefault();
}


public virtual async Task<T> GetByIdAsync(int id)
{
return await _dbContext.Set<T>().FindAsync(id);
Expand Down
1 change: 1 addition & 0 deletions src/Infrastructure/Logging/LoggerAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public void LogWarning(string message, params object[] args)
{
_logger.LogWarning(message, args);
}

public void LogInformation(string message, params object[] args)
{
_logger.LogInformation(message, args);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using ApplicationCore.Exceptions;
using ApplicationCore.Interfaces;
using ApplicationCore.Services;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Moq;
using System;
using Xunit;

namespace UnitTests.ApplicationCore.Services.BasketServiceTests
{
public class SetQuantities
{
private int _invalidId = -1;
private Mock<IAsyncRepository<Basket>> _mockBasketRepo;

public SetQuantities()
{
_mockBasketRepo = new Mock<IAsyncRepository<Basket>>();
}

[Fact]
public async void ThrowsGivenInvalidBasketId()
{
var basketService = new BasketService(_mockBasketRepo.Object, null, null, null);

await Assert.ThrowsAsync<BasketNotFoundException>(async () =>
await basketService.SetQuantities(_invalidId, new System.Collections.Generic.Dictionary<string, int>()));
}

[Fact]
public async void ThrowsGivenNullQuantities()
{
var basketService = new BasketService(null, null, null, null);

await Assert.ThrowsAsync<ArgumentNullException>(async () =>
await basketService.SetQuantities(123, null));
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using ApplicationCore.Services;
using System;
using Xunit;

namespace UnitTests.ApplicationCore.Services.BasketServiceTests
{
public class TransferBasket
{
[Fact]
public async void ThrowsGivenNullAnonymousId()
{
var basketService = new BasketService(null, null, null, null);

await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync(null, "steve"));
}

[Fact]
public async void ThrowsGivenNullUserId()
{
var basketService = new BasketService(null, null, null, null);

await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync("abcdefg", null));
}
}
}

0 comments on commit b864be9

Please sign in to comment.