From 4c0f1dd54156a617637a0eb90794264b15c1042c Mon Sep 17 00:00:00 2001 From: Willem van den Ende Date: Thu, 3 Sep 2026 14:06:24 +0100 Subject: [PATCH] Let custom matcher provide clear failure messages --- exercises/show-dont-tell/.gitignore | 1 + .../tests/OrderTests/OrderStateConstraint.cs | 53 ++++++++++++++----- .../tests/OrderTests/OrderTests.csproj | 4 +- .../tests/OrderTests/OrderTotalTests.cs | 2 +- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/exercises/show-dont-tell/.gitignore b/exercises/show-dont-tell/.gitignore index 53d8e7b..a62daa5 100644 --- a/exercises/show-dont-tell/.gitignore +++ b/exercises/show-dont-tell/.gitignore @@ -17,3 +17,4 @@ obj/ ## NuGet local config (workaround for locked ~/.nuget) nuget.config +*.log diff --git a/exercises/show-dont-tell/tests/OrderTests/OrderStateConstraint.cs b/exercises/show-dont-tell/tests/OrderTests/OrderStateConstraint.cs index 5024fc9..430ed5f 100644 --- a/exercises/show-dont-tell/tests/OrderTests/OrderStateConstraint.cs +++ b/exercises/show-dont-tell/tests/OrderTests/OrderStateConstraint.cs @@ -12,9 +12,7 @@ namespace OrderTests; public static class Has { public static IResolveConstraint OrderState(decimal expectedTotal, decimal[] expectedLineValues) - { - return new OrderStateConstraint(expectedTotal, expectedLineValues); - } + => new OrderStateConstraint(expectedTotal, expectedLineValues); } public class OrderStateConstraint : Constraint @@ -23,27 +21,54 @@ public class OrderStateConstraint : Constraint private readonly decimal[] _expectedLineValues; public OrderStateConstraint(decimal expectedTotal, decimal[] expectedLineValues) - : base($"order with total {expectedTotal} and line values [{string.Join(", ", expectedLineValues)}]") { _expectedTotal = expectedTotal; _expectedLineValues = expectedLineValues; } + public override string Description => + $"order with total {_expectedTotal} and line values [{string.Join(", ", _expectedLineValues)}]"; + public override ConstraintResult ApplyTo(TActual actual) { var order = (Order)(object)actual!; var actualTotal = order.Total; var actualLineValues = order.Lines.Select(l => l.Value).ToArray(); - var totalMatch = actualTotal == _expectedTotal; - var linesMatch = actualLineValues.SequenceEqual(_expectedLineValues); + var details = new List(); + if (actualTotal != _expectedTotal) + details.Add($"Total: expected {_expectedTotal}, but was {actualTotal}"); + if (!actualLineValues.SequenceEqual(_expectedLineValues)) + details.Add( + $"Line values: expected [{string.Join(", ", _expectedLineValues)}], " + + $"but was [{string.Join(", ", actualLineValues)}]"); - var messages = new List(); - if (!totalMatch) - messages.Add($"Total: expected {_expectedTotal}, got {actualTotal}"); - if (!linesMatch) - messages.Add($"Line values: expected [{string.Join(", ", _expectedLineValues)}], got [{string.Join(", ", actualLineValues)}]"); - - return new ConstraintResult(this, actual, totalMatch && linesMatch); + return new OrderStateResult(this, actual!, details.Count == 0, details); } -} \ No newline at end of file + + /// + /// A ConstraintResult that carries the per-field mismatch details and + /// writes them as additional lines in the failure message, e.g. + /// + /// Expected: order with total 210 and line values [160, 50] + /// But was: <Order> + /// Total: expected 210, but was 250 + /// Line values: expected [160, 50], but was [200, 50] + /// + private sealed class OrderStateResult : ConstraintResult + { + private readonly IReadOnlyList _details; + + public OrderStateResult(Constraint constraint, object? actual, bool isSuccess, IReadOnlyList details) + : base(constraint, actual, isSuccess) + { + _details = details; + } + + public override void WriteAdditionalLinesTo(MessageWriter writer) + { + foreach (var detail in _details) + writer.WriteMessageLine(detail); + } + } +} diff --git a/exercises/show-dont-tell/tests/OrderTests/OrderTests.csproj b/exercises/show-dont-tell/tests/OrderTests/OrderTests.csproj index ee1bc80..b33d1de 100644 --- a/exercises/show-dont-tell/tests/OrderTests/OrderTests.csproj +++ b/exercises/show-dont-tell/tests/OrderTests/OrderTests.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/exercises/show-dont-tell/tests/OrderTests/OrderTotalTests.cs b/exercises/show-dont-tell/tests/OrderTests/OrderTotalTests.cs index dad0859..94608e5 100644 --- a/exercises/show-dont-tell/tests/OrderTests/OrderTotalTests.cs +++ b/exercises/show-dont-tell/tests/OrderTests/OrderTotalTests.cs @@ -18,7 +18,7 @@ public class OrderTotalTests Assert.That(order, Has.OrderState( expectedTotal: 210m, - expectedLineValues: new[] { 160m, 50m })); + expectedLineValues: [160m, 50m])); } [Test]