Scaffold full-stack solution and CI baseline
This commit is contained in:
26
RpgRoller.Tests/RpgRoller.Tests.csproj
Normal file
26
RpgRoller.Tests/RpgRoller.Tests.csproj
Normal file
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RpgRoller\RpgRoller.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
89
RpgRoller.Tests/UnitTest1.cs
Normal file
89
RpgRoller.Tests/UnitTest1.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using RpgRoller.Contracts;
|
||||
using RpgRoller.Services;
|
||||
|
||||
namespace RpgRoller.Tests;
|
||||
|
||||
public sealed class UnitTest1 : IClassFixture<WebApplicationFactory<Program>>
|
||||
{
|
||||
private readonly HttpClient m_Client;
|
||||
|
||||
public UnitTest1(WebApplicationFactory<Program> factory)
|
||||
{
|
||||
m_Client = factory.WithWebHostBuilder(builder =>
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.RemoveAll<IDiceRoller>();
|
||||
services.AddSingleton<IDiceRoller>(new FixedDiceRoller(7));
|
||||
})).CreateClient();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetHealth_ReturnsOkPayload()
|
||||
{
|
||||
var response = await m_Client.GetAsync("/api/health");
|
||||
var payload = await response.Content.ReadFromJsonAsync<HealthResponse>();
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(payload);
|
||||
Assert.Equal("ok", payload.Status);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1, "Dice must have at least 2 sides.")]
|
||||
[InlineData(1001, "Dice must have at most 1000 sides.")]
|
||||
public async Task Roll_WithInvalidSides_ReturnsBadRequest(int sides, string expectedError)
|
||||
{
|
||||
var response = await m_Client.GetAsync($"/api/roll/{sides}");
|
||||
var payload = await response.Content.ReadFromJsonAsync<ApiError>();
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.NotNull(payload);
|
||||
Assert.Equal(expectedError, payload.Error);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2)]
|
||||
[InlineData(1000)]
|
||||
public async Task Roll_WithValidSides_ReturnsExpectedResult(int sides)
|
||||
{
|
||||
var response = await m_Client.GetAsync($"/api/roll/{sides}");
|
||||
var payload = await response.Content.ReadFromJsonAsync<RollResponse>();
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(payload);
|
||||
Assert.Equal(sides, payload.Sides);
|
||||
Assert.Equal(Math.Min(7, sides), payload.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RandomDiceRoller_ProducesValueWithinRange()
|
||||
{
|
||||
var roller = new RandomDiceRoller();
|
||||
|
||||
for (var i = 0; i < 200; i += 1)
|
||||
{
|
||||
var value = roller.Roll(6);
|
||||
Assert.InRange(value, 1, 6);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FixedDiceRoller : IDiceRoller
|
||||
{
|
||||
private readonly int m_Result;
|
||||
|
||||
public FixedDiceRoller(int result)
|
||||
{
|
||||
m_Result = result;
|
||||
}
|
||||
|
||||
public int Roll(int sides)
|
||||
{
|
||||
return Math.Min(m_Result, sides);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
RpgRoller.Tests/coverlet.runsettings
Normal file
13
RpgRoller.Tests/coverlet.runsettings
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RunSettings>
|
||||
<DataCollectionRunSettings>
|
||||
<DataCollectors>
|
||||
<DataCollector friendlyName="XPlat code coverage">
|
||||
<Configuration>
|
||||
<Format>cobertura</Format>
|
||||
<ExcludeByAttribute>GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute</ExcludeByAttribute>
|
||||
</Configuration>
|
||||
</DataCollector>
|
||||
</DataCollectors>
|
||||
</DataCollectionRunSettings>
|
||||
</RunSettings>
|
||||
Reference in New Issue
Block a user