Skip to content

Commit

Permalink
refactor(services)!: add Player mapping to UpdateAsync, add test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
nanotaboada committed Apr 19, 2024
1 parent 6b07f5f commit 4fa5795
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public async Task GivenPostAsync_WhenServiceRetrieveByIdAsyncReturnsPlayer_ThenR
public async Task GivenPostAsync_WhenServiceRetrieveByIdAsyncReturnsNull_ThenResponseStatusCodeShouldBe201Created()
{
// Arrange
var player = PlayerDataBuilder.SeedOneById(12);
var player = PlayerDataBuilder.SeedOneNew();

var service = new Mock<IPlayerService>();
service
Expand Down
80 changes: 80 additions & 0 deletions Dotnet.Samples.AspNetCore.WebApi.Tests/PlayerServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ public void Dispose()
GC.SuppressFinalize(this);
}

/* -------------------------------------------------------------------------
* Create
* ---------------------------------------------------------------------- */

[Fact]
[Trait("Category", "CreateAsync")]
public async Task GivenCreateAsync_WhenInvokedWithPlayer_ThenShouldAddPlayerToContextAndRemovePlayersFromCache()
{
// Arrange
var player = PlayerDataBuilder.SeedOneNew();
var logger = PlayerMocks.LoggerMock<PlayerService>();
var memoryCache = PlayerMocks.MemoryCacheMock(It.IsAny<object>());

var service = new PlayerService(_context, logger.Object, memoryCache.Object);

// Act
await service.CreateAsync(player);
var result = await _context.Players.FindAsync(player.Id);

// Assert
result.Should().NotBeNull();
memoryCache.Verify(cache => cache.Remove(It.IsAny<object>()), Times.Exactly(1));
}

/* -------------------------------------------------------------------------
* Retrieve
* ---------------------------------------------------------------------- */

[Fact]
[Trait("Category", "RetrieveAsync")]
public async Task GivenRetrieveAsync_WhenInvoked_ThenShouldReturnAllPlayers()
Expand Down Expand Up @@ -97,6 +125,58 @@ public async Task GivenRetrieveByIdAsync_WhenInvokedWithPlayerId_ThenShouldRetur
result.Should().BeEquivalentTo(player);
}

/* -------------------------------------------------------------------------
* Update
* ---------------------------------------------------------------------- */

[Fact]
[Trait("Category", "UpdateAsync")]
public async Task GivenUpdateAsync_WhenInvokedWithPlayer_ThenShouldModifyPlayerInContextAndRemovePlayersFromCache()
{
// Arrange
var player = PlayerDataBuilder.SeedOneById(1);
var logger = PlayerMocks.LoggerMock<PlayerService>();
var memoryCache = PlayerMocks.MemoryCacheMock(It.IsAny<object>());

var service = new PlayerService(_context, logger.Object, memoryCache.Object);

// Act
player.FirstName = "Emiliano";
player.MiddleName = "";
await service.UpdateAsync(player);
var result = await _context.Players.FindAsync(player.Id);

// Assert
result!.FirstName.Should().Be(player.FirstName);
memoryCache.Verify(cache => cache.Remove(It.IsAny<object>()), Times.Exactly(1));
}

/* -------------------------------------------------------------------------
* Delete
* ---------------------------------------------------------------------- */

[Fact]
[Trait("Category", "DeleteAsync")]
public async Task GivenDeleteAsync_WhenInvokedWithPlayerId_ThenShouldDeletePlayerInContextAndRemovePlayersFromCache()
{
// Arrange
var player = PlayerDataBuilder.SeedOneNew();
var logger = PlayerMocks.LoggerMock<PlayerService>();
var memoryCache = PlayerMocks.MemoryCacheMock(It.IsAny<object>());
await _context.AddAsync(player);
await _context.SaveChangesAsync();

var service = new PlayerService(_context, logger.Object, memoryCache.Object);

// Act
await service.DeleteAsync(player.Id);
var result = await _context.Players.FindAsync(player.Id);

// Assert
result.Should().BeNull();
memoryCache.Verify(cache => cache.Remove(It.IsAny<object>()), Times.Exactly(1));
}

private async Task<long> ExecutionTimeAsync(Func<Task> awaitable)
{
var stopwatch = new Stopwatch();
Expand Down
33 changes: 17 additions & 16 deletions Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDataBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.IO.Compression;
using System.Text.Json;
using System.Text.Json;
using Dotnet.Samples.AspNetCore.WebApi.Models;

namespace Dotnet.Samples.AspNetCore.WebApi.Data;
Expand All @@ -11,6 +10,22 @@ public static Player SeedOneById(int id)
return SeedWithStarting11().SingleOrDefault(player => player.Id == id) ?? new Player();
}

public static Player SeedOneNew() =>
new()
{
Id = 12,
FirstName = "Leandro",
MiddleName = "Daniel",
LastName = "Paredes",
DateOfBirth = new DateTime(1994, 06, 29, 0, 0, 0, DateTimeKind.Utc),
SquadNumber = 5,
Position = "Defensive Midfield",
AbbrPosition = "DM",
Team = "AS Roma",
League = "Serie A",
Starting11 = false
};

public static List<Player> SeedWithStarting11()
{
var players = new List<Player>
Expand Down Expand Up @@ -165,20 +180,6 @@ public static List<Player> SeedWithStarting11()
Team = "Manchester City",
League = "Premier League",
Starting11 = true,
},
new()
{
Id = 12,
FirstName = "Leandro",
MiddleName = "Daniel",
LastName = "Paredes",
DateOfBirth = new DateTime(1994, 06, 29, 0, 0, 0, DateTimeKind.Utc),
SquadNumber = 5,
Position = "Defensive Midfield",
AbbrPosition = "DM",
Team = "AS Roma",
League = "Serie A",
Starting11 = false
}
};

Expand Down
22 changes: 22 additions & 0 deletions Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDataExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Dotnet.Samples.AspNetCore.WebApi.Models;

namespace Dotnet.Samples.AspNetCore.WebApi.Data;

public static class PlayerDataExtensions
{
/// <summary>
/// Simple extension method to map all properties of a Player
/// </summary>
public static void MapFrom(this Player target, Player source)
{
target.FirstName = source.FirstName;
target.MiddleName = source.MiddleName;
target.LastName = source.LastName;
target.DateOfBirth = source.DateOfBirth;
target.SquadNumber = source.SquadNumber;
target.Position = source.Position;
target.Team = source.Team;
target.League = source.League;
target.Starting11 = source.Starting11;
}
}
18 changes: 12 additions & 6 deletions Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Dotnet.Samples.AspNetCore.WebApi.Models;
using Dotnet.Samples.AspNetCore.WebApi.Data;
using Dotnet.Samples.AspNetCore.WebApi.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;

Expand Down Expand Up @@ -80,9 +81,14 @@ Use multiple environments in ASP.NET Core

public async Task UpdateAsync(Player player)
{
if (await _playerContext.Players.FindAsync(player.Id) != null)
var entity = await _playerContext.Players.FindAsync(player.Id);

if (entity != null)
{
_playerContext.Entry(player).State = EntityState.Modified;
// TODO: Add AutoMapper
entity.MapFrom(player);

_playerContext.Entry(entity).State = EntityState.Modified;
await _playerContext.SaveChangesAsync();
_memoryCache.Remove(MemoryCache_Key_RetrieveAsync);
}
Expand All @@ -94,11 +100,11 @@ public async Task UpdateAsync(Player player)

public async Task DeleteAsync(long id)
{
var player = await _playerContext.Players.FindAsync(id);
var entity = await _playerContext.Players.FindAsync(id);

if (player != null)
if (entity != null)
{
_playerContext.Entry(player).State = EntityState.Deleted;
_playerContext.Entry(entity).State = EntityState.Deleted;
await _playerContext.SaveChangesAsync();
_memoryCache.Remove(MemoryCache_Key_RetrieveAsync);
}
Expand Down

0 comments on commit 4fa5795

Please sign in to comment.