Add Order and OrderBook domains with test suites

This commit is contained in:
2026-10-01 11:38:06 +01:00
commit 9f7d4e6a4f
16 changed files with 493 additions and 0 deletions
@@ -0,0 +1,114 @@
using NUnit.Framework;
using OrderBookDomain;
namespace OrderBookTests;
public class OrderBookLifecycleTests
{
private static readonly DateTimeOffset Day0 = new(2025, 6, 1, 0, 0, 0, TimeSpan.Zero);
private static DateTimeOffset At(int day) => Day0.AddDays(day);
[Test]
public void FinalizeThenPay_MovesOrderThroughTwoStates()
{
var book = new OrderBook();
var order = book.OpenOrder("anna");
book.FinalizeOrder(order.Id, At(1));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.WaitingForPayment));
book.PayOrder(order.Id, At(2));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Fulfilling));
}
[Test]
public void PayThenShip_DeliversTheOrder()
{
var book = new OrderBook();
var order = book.OpenOrder("anna");
book.FinalizeOrder(order.Id, At(1));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.WaitingForPayment));
book.PayOrder(order.Id, At(2));
book.ShipOrder(order.Id);
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Delivered));
}
[Test]
public void PayWithinWindow_ThenLatePayOnSecondOrder_CancelsOnlyThatOrder()
{
var book = new OrderBook();
var first = book.OpenOrder("anna");
var second = book.OpenOrder("bram");
book.FinalizeOrder(first.Id, At(1));
book.FinalizeOrder(second.Id, At(1));
Assert.That(book.Orders, Has.Count.EqualTo(2));
book.PayOrder(first.Id, At(5));
Assert.That(book.GetOrder(first.Id).Status, Is.EqualTo(OrderStatus.Fulfilling));
Assert.Throws<InvalidOperationException>(() => book.PayOrder(second.Id, At(30)));
Assert.That(book.GetOrder(second.Id).Status, Is.EqualTo(OrderStatus.Cancelled));
}
[Test]
public void PayBeforeFinalize_Throws_ThenFinalizeStillWorks()
{
var book = new OrderBook();
var order = book.OpenOrder("anna");
Assert.Throws<InvalidOperationException>(() => book.PayOrder(order.Id, At(1)));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Pending));
book.FinalizeOrder(order.Id, At(2));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.WaitingForPayment));
}
[Test]
public void CancelPendingOrder_ThenPayAfterCancel_ThrowsAgain()
{
var book = new OrderBook();
var order = book.OpenOrder("anna");
book.CancelOrder(order.Id);
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Cancelled));
Assert.Throws<InvalidOperationException>(() => book.PayOrder(order.Id, At(1)));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Cancelled));
}
[Test]
public void ShippedOrder_CannotBeCancelled()
{
var book = new OrderBook();
var order = book.OpenOrder("anna");
book.FinalizeOrder(order.Id, At(1));
book.PayOrder(order.Id, At(2));
book.ShipOrder(order.Id);
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Delivered));
Assert.Throws<InvalidOperationException>(() => book.CancelOrder(order.Id));
Assert.That(book.GetOrder(order.Id).Status, Is.EqualTo(OrderStatus.Delivered));
}
[Test]
public void TwoCustomers_InterleaveTransitions_Independently()
{
var book = new OrderBook();
var annas = book.OpenOrder("anna");
var brams = book.OpenOrder("bram");
book.FinalizeOrder(brams.Id, At(1));
Assert.That(book.GetOrder(annas.Id).Status, Is.EqualTo(OrderStatus.Pending));
Assert.That(book.GetOrder(brams.Id).Status, Is.EqualTo(OrderStatus.WaitingForPayment));
book.PayOrder(brams.Id, At(2));
book.CancelOrder(annas.Id);
Assert.That(book.GetOrder(annas.Id).Status, Is.EqualTo(OrderStatus.Cancelled));
Assert.That(book.GetOrder(brams.Id).Status, Is.EqualTo(OrderStatus.Fulfilling));
}
}
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\OrderBookDomain\OrderBookDomain.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
using NUnit.Framework;
using OrderDomain;
namespace OrderTests;
public class OrderCompletionTests
{
[Test]
public void CompletedOrder_TotalIsCorrect()
{
var order = new Order();
order.AddLine(100m, 1);
order.Complete();
Assert.That(order.Total, Is.EqualTo(100m));
}
}
+16
View File
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\OrderDomain\OrderDomain.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,90 @@
using NUnit.Framework;
using OrderDomain;
namespace OrderTests;
public class OrderTotalTests
{
[Test]
public void DiscountOnFirstLine_TotalAndLineValues()
{
var order = new Order();
order.AddLine(100m, 2); // line 0: 200 → 160 with discount
order.AddLine(50m, 1); // line 1: 50
order.ApplyDiscount(0);
Assert.That(order.Total, Is.EqualTo(210m));
Assert.That(order.Lines[0].Value, Is.EqualTo(160m));
Assert.That(order.Lines[1].Value, Is.EqualTo(50m));
}
[Test]
public void DiscountOnSecondLine_TotalAndLineValues()
{
var order = new Order();
order.AddLine(100m, 2); // line 0: 200
order.AddLine(50m, 1); // line 1: 50 → 40 with discount
order.ApplyDiscount(1);
Assert.That(order.Total, Is.EqualTo(240m));
Assert.That(order.Lines[0].Value, Is.EqualTo(200m));
Assert.That(order.Lines[1].Value, Is.EqualTo(40m));
}
[Test]
public void DiscountOnBothLines_TotalAndLineValues()
{
var order = new Order();
order.AddLine(100m, 2); // line 0: 200 → 160
order.AddLine(50m, 1); // line 1: 50 → 40
order.ApplyDiscount(0);
order.ApplyDiscount(1);
Assert.That(order.Total, Is.EqualTo(200m));
Assert.That(order.Lines[0].Value, Is.EqualTo(160m));
Assert.That(order.Lines[1].Value, Is.EqualTo(40m));
}
[Test]
public void NoDiscount_TotalAndLineValues()
{
var order = new Order();
order.AddLine(100m, 2); // line 0: 200
order.AddLine(50m, 1); // line 1: 50
Assert.That(order.Total, Is.EqualTo(250m));
Assert.That(order.Lines[0].Value, Is.EqualTo(200m));
Assert.That(order.Lines[1].Value, Is.EqualTo(50m));
}
[Test]
public void SingleLineWithDiscount_TotalAndValue()
{
var order = new Order();
order.AddLine(75m, 4); // line 0: 300 → 240
order.ApplyDiscount(0);
Assert.That(order.Total, Is.EqualTo(240m));
Assert.That(order.Lines[0].Value, Is.EqualTo(240m));
}
[Test]
public void ThreeLinesOneDiscount_TotalAndLineValues()
{
var order = new Order();
order.AddLine(20m, 1); // line 0: 20
order.AddLine(30m, 2); // line 1: 60 → 48
order.AddLine(10m, 3); // line 2: 30
order.ApplyDiscount(1);
Assert.That(order.Total, Is.EqualTo(98m));
Assert.That(order.Lines[0].Value, Is.EqualTo(20m));
Assert.That(order.Lines[1].Value, Is.EqualTo(48m));
Assert.That(order.Lines[2].Value, Is.EqualTo(30m));
}
}