Skip to content

Commit

Permalink
feat: add unit tests for Retrieve methods of Service layer
Browse files Browse the repository at this point in the history
  • Loading branch information
nanotaboada committed Feb 14, 2024
1 parent c4d959f commit 6f23cf1
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Moq.EntityFrameworkCore" Version="7.0.0.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand All @@ -24,8 +23,8 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Dotnet.AspNetCore.Samples.WebApi\Dotnet.AspNetCore.Samples.WebApi.csproj" />
<ItemGroup>
<ProjectReference Include="..\Dotnet.AspNetCore.Samples.WebApi\Dotnet.AspNetCore.Samples.WebApi.csproj" />
</ItemGroup>

</Project>
100 changes: 93 additions & 7 deletions Dotnet.AspNetCore.Samples.WebApi.Tests/PlayerServiceTests.cs
Original file line number Diff line number Diff line change
@@ -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<PlayerContext> dbContextOptions;

public PlayerServiceTests()
{
dbConnection = new SqliteConnection("Filename=:memory:");
dbConnection.Open();

dbContextOptions = new DbContextOptionsBuilder<PlayerContext>()
.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<PlayerContext>();
context.Setup(context => context.Players).ReturnsDbSet(players);
var players = PlayerDataBuilder.SeedWithDeserializedJson();
var context = CreatePlayerContext();
var logger = new Mock<ILogger<PlayerService>>();
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<ILogger<PlayerService>>();
var memoryCache = new MemoryCache(new MemoryCacheOptions());

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

// Act
var first = await ExecutionTimeAsync(() => service.RetrieveAsync());
Expand All @@ -41,4 +107,24 @@ private async Task<long> ExecutionTimeAsync(Func<Task> 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<ILogger<PlayerService>>();
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<Player>();
result.Should().BeEquivalentTo(player);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ HTTP POST
[HttpPost]
public async Task<ActionResult<Player>> PostPlayer(Player player)
{
if (await _playerService.RetrieveById(player.Id) != null)
if (await _playerService.RetrieveByIdAsync(player.Id) != null)
{
return Conflict();
}
Expand Down Expand Up @@ -74,7 +74,7 @@ public async Task<ActionResult<IEnumerable<Player>>> GetPlayers()
[HttpGet("{id}")]
public async Task<ActionResult<Player>> GetPlayer(long id)
{
var player = await _playerService.RetrieveById(id);
var player = await _playerService.RetrieveByIdAsync(id);

Check warning on line 77 in Dotnet.AspNetCore.Samples.WebApi/Controllers/PlayersController.cs

View check run for this annotation

Codecov / codecov/patch

Dotnet.AspNetCore.Samples.WebApi/Controllers/PlayersController.cs#L77

Added line #L77 was not covered by tests

if (player != null)
{
Expand All @@ -100,7 +100,7 @@ public async Task<IActionResult> PutPlayer(long id, Player player)
{
return BadRequest();
}
else if (await _playerService.RetrieveById(id) == null)
else if (await _playerService.RetrieveByIdAsync(id) == null)
{
return NotFound();
}
Expand All @@ -121,7 +121,7 @@ HTTP DELETE
[HttpDelete("{id}")]
public async Task<IActionResult> DeletePlayer(long id)
{
if (await _playerService.RetrieveById(id) == null)
if (await _playerService.RetrieveByIdAsync(id) == null)
{
return NotFound();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Dotnet.AspNetCore.Samples.WebApi.Data;
using Dotnet.AspNetCore.Samples.WebApi.Models;
using Microsoft.EntityFrameworkCore;

namespace Dotnet.AspNetCore.Samples.WebApi;

Expand All @@ -10,9 +11,10 @@ public static void Seed(IApplicationBuilder applicationBuilder)
using (var scope = applicationBuilder.ApplicationServices.CreateScope())
{
var context = scope.ServiceProvider.GetService<PlayerContext>();

if (context != null)
{
// https://learn.microsoft.com/en-us/ef/core/managing-schemas/ensure-created
context.Database.EnsureCreated();

if (!context.Players.Any())
Expand Down
Loading

0 comments on commit 6f23cf1

Please sign in to comment.