diff --git a/Dotnet.AspNetCore.Samples.WebApi.Tests/Dotnet.AspNetCore.Samples.WebApi.Tests.csproj b/Dotnet.AspNetCore.Samples.WebApi.Tests/Dotnet.AspNetCore.Samples.WebApi.Tests.csproj
index 0f3b4a6..4ebd07b 100644
--- a/Dotnet.AspNetCore.Samples.WebApi.Tests/Dotnet.AspNetCore.Samples.WebApi.Tests.csproj
+++ b/Dotnet.AspNetCore.Samples.WebApi.Tests/Dotnet.AspNetCore.Samples.WebApi.Tests.csproj
@@ -12,7 +12,6 @@
-
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -24,8 +23,8 @@
-
-
+
+
diff --git a/Dotnet.AspNetCore.Samples.WebApi.Tests/PlayerServiceTests.cs b/Dotnet.AspNetCore.Samples.WebApi.Tests/PlayerServiceTests.cs
index f71afd8..f2e05fd 100644
--- a/Dotnet.AspNetCore.Samples.WebApi.Tests/PlayerServiceTests.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi.Tests/PlayerServiceTests.cs
@@ -1,28 +1,94 @@
+using System.Data.Common;
using System.Diagnostics;
using Dotnet.AspNetCore.Samples.WebApi.Data;
using Dotnet.AspNetCore.Samples.WebApi.Models;
using Dotnet.AspNetCore.Samples.WebApi.Services;
using FluentAssertions;
+using Microsoft.Data.Sqlite;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Moq;
-using Moq.EntityFrameworkCore;
namespace Dotnet.AspNetCore.Samples.WebApi.Tests;
-public class PlayerServiceTests
+public class PlayerServiceTests : IDisposable
{
+ private readonly DbConnection dbConnection;
+ private readonly DbContextOptions dbContextOptions;
+
+ public PlayerServiceTests()
+ {
+ dbConnection = new SqliteConnection("Filename=:memory:");
+ dbConnection.Open();
+
+ dbContextOptions = new DbContextOptionsBuilder()
+ .UseSqlite(dbConnection)
+ .Options;
+
+ using var context = new PlayerContext(dbContextOptions);
+
+ if (context.Database.EnsureCreated())
+ {
+ using var dbCommand = context.Database.GetDbConnection().CreateCommand();
+
+ dbCommand.CommandText = """
+ CREATE TABLE IF NOT EXISTS "players"
+ (
+ "id" INTEGER,
+ "firstName" TEXT NOT NULL,
+ "middleName" TEXT,
+ "lastName" TEXT NOT NULL,
+ "dateOfBirth" TEXT,
+ "squadNumber" INTEGER NOT NULL,
+ "position" TEXT NOT NULL,
+ "abbrPosition" TEXT,
+ "team" TEXT,
+ "league" TEXT,
+ "starting11" BOOLEAN,
+ PRIMARY KEY("id")
+ );
+ """;
+
+ dbCommand.ExecuteNonQuery();
+ }
+
+ context.AddRange(PlayerDataBuilder.SeedWithDeserializedJson());
+ context.SaveChanges();
+ }
+
+ PlayerContext CreatePlayerContext() => new PlayerContext(dbContextOptions);
+ public void Dispose() => dbConnection.Dispose();
+
[Fact]
[Trait("Category", "Retrieve")]
- public async Task GivenRetrieve_WhenInvokedTwice_ThenSecondExecutionTimeShouldBeLessThanFirst()
+ public async Task GivenRetrieveAsync_WhenInvoked_ThenShouldReturnAllPlayers()
{
// Arrange
- var players = PlayerDataBuilder.SeedWithStarting11().ToList();
- var context = new Mock();
- context.Setup(context => context.Players).ReturnsDbSet(players);
+ var players = PlayerDataBuilder.SeedWithDeserializedJson();
+ var context = CreatePlayerContext();
var logger = new Mock>();
var memoryCache = new MemoryCache(new MemoryCacheOptions());
- var service = new PlayerService(context.Object, logger.Object, memoryCache);
+
+ var service = new PlayerService(context, logger.Object, memoryCache);
+
+ // Act
+ var result = await service.RetrieveAsync();
+
+ // Assert
+ result.Should().BeEquivalentTo(players);
+ }
+
+ [Fact]
+ [Trait("Category", "Retrieve")]
+ public async Task GivenRetrieveAsync_WhenInvokedTwice_ThenSecondExecutionTimeShouldBeLessThanFirst()
+ {
+ // Arrange
+ var context = CreatePlayerContext();
+ var logger = new Mock>();
+ var memoryCache = new MemoryCache(new MemoryCacheOptions());
+
+ var service = new PlayerService(context, logger.Object, memoryCache);
// Act
var first = await ExecutionTimeAsync(() => service.RetrieveAsync());
@@ -41,4 +107,24 @@ private async Task ExecutionTimeAsync(Func awaitable)
return stopwatch.ElapsedMilliseconds;
}
+
+ [Fact]
+ [Trait("Category", "Retrieve")]
+ public async Task GivenRetrieveByIdAsync_WhenInvokedWithPlayerId_ThenShouldReturnThePlayer()
+ {
+ // Arrange
+ var player = PlayerDataBuilder.SeedOneById(10);
+ var context = CreatePlayerContext();
+ var logger = new Mock>();
+ var memoryCache = new MemoryCache(new MemoryCacheOptions());
+
+ var service = new PlayerService(context, logger.Object, memoryCache);
+
+ // Act
+ var result = await service.RetrieveByIdAsync(10);
+
+ // Assert
+ result.Should().BeOfType();
+ result.Should().BeEquivalentTo(player);
+ }
}
diff --git a/Dotnet.AspNetCore.Samples.WebApi/Controllers/PlayersController.cs b/Dotnet.AspNetCore.Samples.WebApi/Controllers/PlayersController.cs
index ec738a9..7d80a19 100644
--- a/Dotnet.AspNetCore.Samples.WebApi/Controllers/PlayersController.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi/Controllers/PlayersController.cs
@@ -38,7 +38,7 @@ HTTP POST
[HttpPost]
public async Task> PostPlayer(Player player)
{
- if (await _playerService.RetrieveById(player.Id) != null)
+ if (await _playerService.RetrieveByIdAsync(player.Id) != null)
{
return Conflict();
}
@@ -74,7 +74,7 @@ public async Task>> GetPlayers()
[HttpGet("{id}")]
public async Task> GetPlayer(long id)
{
- var player = await _playerService.RetrieveById(id);
+ var player = await _playerService.RetrieveByIdAsync(id);
if (player != null)
{
@@ -100,7 +100,7 @@ public async Task PutPlayer(long id, Player player)
{
return BadRequest();
}
- else if (await _playerService.RetrieveById(id) == null)
+ else if (await _playerService.RetrieveByIdAsync(id) == null)
{
return NotFound();
}
@@ -121,7 +121,7 @@ HTTP DELETE
[HttpDelete("{id}")]
public async Task DeletePlayer(long id)
{
- if (await _playerService.RetrieveById(id) == null)
+ if (await _playerService.RetrieveByIdAsync(id) == null)
{
return NotFound();
}
diff --git a/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerContextInitializer.cs b/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerContextInitializer.cs
index e493168..8422195 100644
--- a/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerContextInitializer.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerContextInitializer.cs
@@ -1,5 +1,6 @@
using Dotnet.AspNetCore.Samples.WebApi.Data;
using Dotnet.AspNetCore.Samples.WebApi.Models;
+using Microsoft.EntityFrameworkCore;
namespace Dotnet.AspNetCore.Samples.WebApi;
@@ -10,9 +11,10 @@ public static void Seed(IApplicationBuilder applicationBuilder)
using (var scope = applicationBuilder.ApplicationServices.CreateScope())
{
var context = scope.ServiceProvider.GetService();
-
+
if (context != null)
{
+ // https://learn.microsoft.com/en-us/ef/core/managing-schemas/ensure-created
context.Database.EnsureCreated();
if (!context.Players.Any())
diff --git a/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerDataBuilder.cs b/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerDataBuilder.cs
index f70ab4b..e698167 100644
--- a/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerDataBuilder.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi/Data/PlayerDataBuilder.cs
@@ -5,7 +5,203 @@ namespace Dotnet.AspNetCore.Samples.WebApi.Data;
public static class PlayerDataBuilder
{
- public static Player[] SeedWithStarting11()
+ public static Player? SeedOneById(int id)
+ {
+ return SeedWithStarting11()
+ .SingleOrDefault(player => player.Id == id);
+ }
+
+ public static List SeedWithStarting11()
+ {
+ var players = new List();
+
+ players.Add(
+ new Player
+ {
+ Id = 1,
+ FirstName = "Damián",
+ MiddleName = "Emiliano",
+ LastName = "Martínez",
+ DateOfBirth = new DateTime(1992, 9, 1, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 23,
+ Position = "Goalkeeper",
+ AbbrPosition = "GK",
+ Team = "Aston Villa FC",
+ League = "Premier League",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 2,
+ FirstName = "Nahuel",
+ LastName = "Molina",
+ DateOfBirth = new DateTime(1998, 4, 5, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 26,
+ Position = "Right-Back",
+ AbbrPosition = "RB",
+ Team = "Altético Madrid",
+ League = "La Liga",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 3,
+ FirstName = "Cristian",
+ MiddleName = "Gabriel",
+ LastName = "Romero",
+ DateOfBirth = new DateTime(1998, 4, 26, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 13,
+ Position = "Centre-Back",
+ AbbrPosition = "CB",
+ Team = "Tottenham Hotspur",
+ League = "Premier League",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 4,
+ FirstName = "Nicolás",
+ MiddleName = "Hernán Gonzalo",
+ LastName = "Otamendi",
+ DateOfBirth = new DateTime(1988, 2, 11, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 19,
+ Position = "Centre-Back",
+ AbbrPosition = "CB",
+ Team = "SL Benfica",
+ League = "Liga Portugal",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 5,
+ FirstName = "Nicolás",
+ MiddleName = "Alejandro",
+ LastName = "Tagliafico",
+ DateOfBirth = new DateTime(1992, 8, 30, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 3,
+ Position = "Left-Back",
+ AbbrPosition = "LB",
+ Team = "Olympique Lyon",
+ League = "Ligue 1",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 6,
+ FirstName = "Ángel",
+ MiddleName = "Fabián",
+ LastName = "Di María",
+ DateOfBirth = new DateTime(1988, 2, 13, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 11,
+ Position = "Right Winger",
+ AbbrPosition = "RW",
+ Team = "SL Benfica",
+ League = "Liga Portugal",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 7,
+ FirstName = "Rodrigo",
+ MiddleName = "Javier",
+ LastName = "de Paul",
+ DateOfBirth = new DateTime(1994, 5, 23, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 7,
+ Position = "Central Midfield",
+ AbbrPosition = "CM",
+ Team = "Altético Madrid",
+ League = "La Liga",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 8,
+ FirstName = "Enzo",
+ MiddleName = "Jeremías",
+ LastName = "Fernández",
+ DateOfBirth = new DateTime(2001, 1, 16, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 24,
+ Position = "Central Midfield",
+ AbbrPosition = "CM",
+ Team = "Chelsea FC",
+ League = "Premier League",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 9,
+ FirstName = "Alexis",
+ LastName = "Mac Allister",
+ DateOfBirth = new DateTime(1998, 12, 23, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 20,
+ Position = "Central Midfield",
+ AbbrPosition = "CM",
+ Team = "Liverpool FC",
+ League = "Premier League",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 10,
+ FirstName = "Lionel",
+ MiddleName = "Andrés",
+ LastName = "Messi",
+ DateOfBirth = new DateTime(1987, 6, 23, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 10,
+ Position = "Right Winger",
+ AbbrPosition = "RW",
+ Team = "Inter Miami CF",
+ League = "Major League Soccer",
+ Starting11 = true,
+ }
+ );
+
+ players.Add(
+ new Player
+ {
+ Id = 11,
+ FirstName = "Julián",
+ LastName = "Álvarez",
+ DateOfBirth = new DateTime(2000, 1, 30, 0, 0, 0, DateTimeKind.Utc),
+ SquadNumber = 9,
+ Position = "Centre-Forward",
+ AbbrPosition = "CF",
+ Team = "Manchester City",
+ League = "Premier League",
+ Starting11 = true,
+ }
+ );
+
+ return players;
+ }
+ public static List SeedWithDeserializedJson()
{
var players = new List();
@@ -15,143 +211,143 @@ public static Player[] SeedWithStarting11()
"firstName": "Damián",
"middleName": "Emiliano",
"lastName": "Martínez",
- "dateOfBirth": "1992-09-01T21:00:00-00:00",
+ "dateOfBirth": "1992-09-01T00:00:00.000Z",
"squadNumber": 23,
"position": "Goalkeeper",
"abbrPosition": "GK",
"team": "Aston Villa FC",
"league": "Premier League",
- "starting11": false
+ "starting11": true
},
{
"id": 2,
"firstName": "Nahuel",
"middleName": null,
"lastName": "Molina",
- "dateOfBirth": "1998-04-05T21:00:00-00:00",
+ "dateOfBirth": "1998-04-05T00:00:00.000Z",
"squadNumber": 26,
"position": "Right-Back",
"abbrPosition": "RB",
"team": "Atlético Madrid",
"league": "La Liga",
- "starting11": false
+ "starting11": true
},
{
"id": 3,
"firstName": "Cristian",
"middleName": "Gabriel",
"lastName": "Romero",
- "dateOfBirth": "1998-04-26T21:00:00-00:00",
+ "dateOfBirth": "1998-04-26T00:00:00.000Z",
"squadNumber": 13,
"position": "Centre-Back",
"abbrPosition": "CB",
"team": "Tottenham Hotspur",
"league": "Premier League",
- "starting11": false
+ "starting11": true
},
{
"id": 4,
"firstName": "Nicolás",
"middleName": "Hernán Gonzalo",
"lastName": "Otamendi",
- "dateOfBirth": "1988-02-11T21:00:00-00:00",
+ "dateOfBirth": "1988-02-11T00:00:00.000Z",
"squadNumber": 19,
"position": "Centre-Back",
"abbrPosition": "CB",
"team": "SL Benfica",
"league": "Liga Portugal",
- "starting11": false
+ "starting11": true
},
{
"id": 5,
"firstName": "Nicolás",
"middleName": "Alejandro",
"lastName": "Tagliafico",
- "dateOfBirth": "1992-08-30T21:00:00-00:00",
+ "dateOfBirth": "1992-08-30T00:00:00.000Z",
"squadNumber": 3,
"position": "Left-Back",
"abbrPosition": "LB",
"team": "Olympique Lyon",
"league": "Ligue 1",
- "starting11": false
+ "starting11": true
},
{
"id": 6,
"firstName": "Ángel",
"middleName": "Fabián",
"lastName": "Di María",
- "dateOfBirth": "1988-02-13T21:00:00-00:00",
+ "dateOfBirth": "1988-02-13T00:00:00.000Z",
"squadNumber": 11,
"position": "Right Winger",
- "abbrPosition": "LW",
+ "abbrPosition": "RW",
"team": "SL Benfica",
"league": "Liga Portugal",
- "starting11": false
+ "starting11": true
},
{
"id": 7,
"firstName": "Rodrigo",
"middleName": "Javier",
"lastName": "de Paul",
- "dateOfBirth": "1994-05-23T21:00:00-00:00",
+ "dateOfBirth": "1994-05-23T00:00:00.000Z",
"squadNumber": 7,
"position": "Central Midfield",
"abbrPosition": "CM",
"team": "Atlético Madrid",
"league": "La Liga",
- "starting11": false
+ "starting11": true
},
{
"id": 8,
"firstName": "Enzo",
"middleName": "Jeremías",
"lastName": "Fernández",
- "dateOfBirth": "2001-01-16T21:00:00-00:00",
+ "dateOfBirth": "2001-01-16T00:00:00.000Z",
"squadNumber": 24,
"position": "Central Midfield",
"abbrPosition": "CM",
"team": "Chelsea FC",
"league": "Premier League",
- "starting11": false
+ "starting11": true
},
{
"id": 9,
"firstName": "Alexis",
"middleName": null,
"lastName": "Mac Allister",
- "dateOfBirth": "1998-12-23T21:00:00-00:00",
+ "dateOfBirth": "1998-12-23T00:00:00.000Z",
"squadNumber": 20,
"position": "Central Midfield",
"abbrPosition": "CM",
"team": "Liverpool FC",
"league": "Premier League",
- "starting11": false
+ "starting11": true
},
{
"id": 10,
"firstName": "Lionel",
"middleName": "Andrés",
"lastName": "Messi",
- "dateOfBirth": "1987-06-23T21:00:00-00:00",
+ "dateOfBirth": "1987-06-23T00:00:00.000Z",
"squadNumber": 10,
"position": "Right Winger",
"abbrPosition": "RW",
"team": "Inter Miami CF",
"league": "Major League Soccer",
- "starting11": false
+ "starting11": true
},
{
"id": 11,
"firstName": "Julián",
"middleName": null,
"lastName": "Álvarez",
- "dateOfBirth": "2000-01-30T21:00:00-00:00",
+ "dateOfBirth": "2000-01-30T00:00:00.000Z",
"squadNumber": 9,
"position": "Centre-Forward",
"abbrPosition": "CF",
"team": "Manchester City",
"league": "Premier League",
- "starting11": false
+ "starting11": true
}]
""";
@@ -163,6 +359,6 @@ public static Player[] SeedWithStarting11()
players.AddRange(starting11);
}
- return players.ToArray();
+ return players;
}
}
diff --git a/Dotnet.AspNetCore.Samples.WebApi/Program.cs b/Dotnet.AspNetCore.Samples.WebApi/Program.cs
index 5e95af7..e4cd65c 100644
--- a/Dotnet.AspNetCore.Samples.WebApi/Program.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi/Program.cs
@@ -1,6 +1,7 @@
using Dotnet.AspNetCore.Samples.WebApi;
using Dotnet.AspNetCore.Samples.WebApi.Models;
using Dotnet.AspNetCore.Samples.WebApi.Services;
+using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
@@ -13,13 +14,8 @@
builder.Services.AddControllers();
-// var localApplicationData = Environment.SpecialFolder.LocalApplicationData;
-// var folderPath = Environment.GetFolderPath(localApplicationData);
-var projectDataFolder = "Data";
-var path = Path.Join(projectDataFolder, "players-sqlite3.db");
-
builder.Services.AddDbContext(options =>
- options.UseSqlite($"Data Source={path}")
+ options.UseSqlite(@"Data Source=Data/players-sqlite3.db")
);
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
diff --git a/Dotnet.AspNetCore.Samples.WebApi/Services/IPlayerService.cs b/Dotnet.AspNetCore.Samples.WebApi/Services/IPlayerService.cs
index 96d32dd..3774c55 100644
--- a/Dotnet.AspNetCore.Samples.WebApi/Services/IPlayerService.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi/Services/IPlayerService.cs
@@ -9,7 +9,7 @@ public interface IPlayerService
public Task> RetrieveAsync();
- public ValueTask RetrieveById(long id);
+ public ValueTask RetrieveByIdAsync(long id);
public Task UpdateAsync(Player player);
diff --git a/Dotnet.AspNetCore.Samples.WebApi/Services/PlayerService.cs b/Dotnet.AspNetCore.Samples.WebApi/Services/PlayerService.cs
index 12e82b2..deaf7b1 100644
--- a/Dotnet.AspNetCore.Samples.WebApi/Services/PlayerService.cs
+++ b/Dotnet.AspNetCore.Samples.WebApi/Services/PlayerService.cs
@@ -57,7 +57,7 @@ public async Task> RetrieveAsync()
}
}
- public ValueTask RetrieveById(long id)
+ public ValueTask RetrieveByIdAsync(long id)
{
return _playerContext.Players.FindAsync(id);
}