From 29b22dba756326fcce28d68c41767d7208815169 Mon Sep 17 00:00:00 2001 From: Eric Sibly Date: Thu, 14 May 2026 08:07:18 -0700 Subject: [PATCH 1/2] - *Enhancement:* Added `AssertorBase.Logs` to enable access to the logs captured during execution of the test for assertion purposes. This is intended to be used in conjunction with the existing `ExpectLogContains` expectation to enable additional (more advanced) assertions against the logs. --- CHANGELOG.md | 3 +++ Common.targets | 2 +- .../Azure/Functions/HttpTriggerTester.cs | 2 +- .../Azure/Functions/ServiceBusTriggerTester.cs | 2 +- src/UnitTestEx/AspNetCore/HttpTesterBase.cs | 6 +++--- .../Assertors/ActionResultAssertor.cs | 10 ++++++---- src/UnitTestEx/Assertors/AssertorBase.cs | 10 ++++++++-- src/UnitTestEx/Assertors/AssertorBaseT.cs | 3 ++- .../Assertors/HttpResponseMessageAssertor.cs | 4 +++- .../HttpResponseMessageAssertorBase.cs | 9 ++++++++- .../HttpResponseMessageAssertorBaseT.cs | 3 ++- .../Assertors/HttpResponseMessageAssertorT.cs | 9 ++++++--- src/UnitTestEx/Assertors/HttpResultAssertor.cs | 13 ++++++++----- src/UnitTestEx/Assertors/ValueAssertor.cs | 12 +++++++----- src/UnitTestEx/Assertors/VoidAssertor.cs | 4 +++- src/UnitTestEx/Generic/GenericTesterBase.cs | 4 ++-- src/UnitTestEx/Generic/GenericTesterBaseT.cs | 2 +- src/UnitTestEx/Hosting/ScopedTypeTester.cs | 4 ++-- src/UnitTestEx/Hosting/TypeTester.cs | 4 ++-- .../PersonControllerTest.cs | 17 ++++++++++++++--- .../ProductFunctionTest.cs | 5 ++++- 21 files changed, 87 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5aceeb..5159701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Represents the **NuGet** versions. +## v5.11.0 +- *Enhancement:* Added `AssertorBase.Logs` to enable access to the logs captured during execution of the test for assertion purposes. This is intended to be used in conjunction with the existing `ExpectLogContains` expectation to enable additional (more advanced) assertions against the logs. + ## v5.10.0 - *Enhancement:* `TestSharedState` updated to enable request-based (isolated) state; with the corresponding `GetHttpRequestId()` method now made public. - *Enhancement:* Added `ApiTesterBase.AddPreRunAction()`, `AddPostRunBeforeExpectationsAction()`, `AddPostRunAfterExpectationsAction()` and `AddPostRunAction()` to enable the addition of actions to be executed at different stages of the `Run`/`RunAsync` process for every underlying test. This will enable the addition of common pre/post processing logic without having to explicitly add to each test. diff --git a/Common.targets b/Common.targets index 8dd083e..b92435c 100644 --- a/Common.targets +++ b/Common.targets @@ -1,6 +1,6 @@  - 5.10.0 + 5.11.0 preview Avanade Avanade diff --git a/src/UnitTestEx.Azure.Functions/Azure/Functions/HttpTriggerTester.cs b/src/UnitTestEx.Azure.Functions/Azure/Functions/HttpTriggerTester.cs index 315b785..323b644 100644 --- a/src/UnitTestEx.Azure.Functions/Azure/Functions/HttpTriggerTester.cs +++ b/src/UnitTestEx.Azure.Functions/Azure/Functions/HttpTriggerTester.cs @@ -146,7 +146,7 @@ public async Task RunAsync(Expression RunAsync(Expression> expre await ExpectationsArranger.AssertAsync(logs, ex).ConfigureAwait(false); - return new VoidAssertor(Owner, ex); + return new VoidAssertor(Owner, logs, ex); } /// diff --git a/src/UnitTestEx/AspNetCore/HttpTesterBase.cs b/src/UnitTestEx/AspNetCore/HttpTesterBase.cs index 85df143..0eb43c6 100644 --- a/src/UnitTestEx/AspNetCore/HttpTesterBase.cs +++ b/src/UnitTestEx/AspNetCore/HttpTesterBase.cs @@ -100,7 +100,7 @@ protected async Task SendAsync(HttpMethod httpMetho Owner.ExecutePostRunBeforeExpectationsActions(this); await AssertExpectationsAsync(res).ConfigureAwait(false); Owner.ExecutePostRunAfterExpectationsActions(this); - return new HttpResponseMessageAssertor(Owner, res); + return new HttpResponseMessageAssertor(Owner, LastLogs, res); } finally { @@ -136,7 +136,7 @@ protected async Task SendAsync(HttpMethod httpMetho Owner.ExecutePostRunBeforeExpectationsActions(this); await AssertExpectationsAsync(res).ConfigureAwait(false); Owner.ExecutePostRunAfterExpectationsActions(this); - return new HttpResponseMessageAssertor(Owner, res); + return new HttpResponseMessageAssertor(Owner, LastLogs, res); } finally { @@ -171,7 +171,7 @@ protected async Task SendAsync(HttpMethod httpMetho Owner.ExecutePostRunBeforeExpectationsActions(this); await AssertExpectationsAsync(res).ConfigureAwait(false); Owner.ExecutePostRunAfterExpectationsActions(this); - return new HttpResponseMessageAssertor(Owner, res); + return new HttpResponseMessageAssertor(Owner, LastLogs, res); } finally { diff --git a/src/UnitTestEx/Assertors/ActionResultAssertor.cs b/src/UnitTestEx/Assertors/ActionResultAssertor.cs index ba86749..6678cb4 100644 --- a/src/UnitTestEx/Assertors/ActionResultAssertor.cs +++ b/src/UnitTestEx/Assertors/ActionResultAssertor.cs @@ -24,8 +24,9 @@ namespace UnitTestEx.Assertors /// /// The owning . /// The . + /// The logs captured during execution. /// The (if any). - public class ActionResultAssertor(TesterBase owner, IActionResult result, Exception? exception) : AssertorBase(owner, exception) + public class ActionResultAssertor(TesterBase owner, IActionResult result, IEnumerable? logs, Exception? exception) : AssertorBase(owner, logs, exception) { /// /// Gets the . @@ -485,16 +486,17 @@ public ActionResultAssertor AssertJson(string json, params string[] pathsToIgnor /// /// The optional requesting with ; otherwise, will default. /// The corresponding . - public HttpResponseMessageAssertor ToHttpResponseMessageAssertor(HttpRequest? httpRequest = null) => ToHttpResponseMessageAssertor(Owner, Result, httpRequest); + public HttpResponseMessageAssertor ToHttpResponseMessageAssertor(HttpRequest? httpRequest = null) => ToHttpResponseMessageAssertor(Owner, Result, LogMessages, httpRequest); /// /// Converts the to an . /// /// The owning . /// The to convert. + /// The log messages captured during execution. /// The optional requesting ; otherwise, will default. /// The corresponding . - internal static HttpResponseMessageAssertor ToHttpResponseMessageAssertor(TesterBase owner, IActionResult result, HttpRequest? httpRequest) + internal static HttpResponseMessageAssertor ToHttpResponseMessageAssertor(TesterBase owner, IActionResult result, IEnumerable? logs, HttpRequest? httpRequest) { var sw = Stopwatch.StartNew(); using var ms = new MemoryStream(); @@ -517,7 +519,7 @@ internal static HttpResponseMessageAssertor ToHttpResponseMessageAssertor(Tester sw.Stop(); owner.LogHttpResponseMessage(hr, sw); - return new HttpResponseMessageAssertor(owner, hr); + return new HttpResponseMessageAssertor(owner, logs, hr); } } } \ No newline at end of file diff --git a/src/UnitTestEx/Assertors/AssertorBase.cs b/src/UnitTestEx/Assertors/AssertorBase.cs index ac2c48f..ade3e9b 100644 --- a/src/UnitTestEx/Assertors/AssertorBase.cs +++ b/src/UnitTestEx/Assertors/AssertorBase.cs @@ -11,8 +11,9 @@ namespace UnitTestEx.Assertors /// Represents the base test assert helper. /// /// The owning . + /// The logs captured during execution. /// The (if any). - public abstract class AssertorBase(TesterBase owner, Exception? exception) + public abstract class AssertorBase(TesterBase owner, IEnumerable? logs, Exception? exception) { private static List>? _assertErrorsExtentions; @@ -28,6 +29,11 @@ public abstract class AssertorBase(TesterBase owner, Exception? exception) /// public TesterBase Owner { get; } = owner ?? throw new ArgumentNullException(nameof(owner)); + /// + /// Gets the log messages captured during execution. + /// + public IEnumerable LogMessages { get; } = logs ?? []; + /// /// Gets the . /// @@ -58,7 +64,7 @@ internal void AssertErrorsUsingExtensions(ApiError[] errors) return; } - if (!Assertor.TryAreErrorsMatched(errors, Array.Empty(), out var errorMessage)) + if (!Assertor.TryAreErrorsMatched(errors, [], out var errorMessage)) Implementor.AssertFail(errorMessage); } } diff --git a/src/UnitTestEx/Assertors/AssertorBaseT.cs b/src/UnitTestEx/Assertors/AssertorBaseT.cs index 06c8c7d..475b75f 100644 --- a/src/UnitTestEx/Assertors/AssertorBaseT.cs +++ b/src/UnitTestEx/Assertors/AssertorBaseT.cs @@ -10,8 +10,9 @@ namespace UnitTestEx.Assertors /// Represents the base test assert helper that distinguishes between and . /// /// The owning . + /// The logs captured during execution. /// The (if any). - public abstract class AssertorBase(TesterBase owner, Exception? exception) : AssertorBase(owner, exception) where TSelf : AssertorBase + public abstract class AssertorBase(TesterBase owner, IEnumerable? logs, Exception? exception) : AssertorBase(owner, logs, exception) where TSelf : AssertorBase { /// /// Asserts that an was thrown during execution. diff --git a/src/UnitTestEx/Assertors/HttpResponseMessageAssertor.cs b/src/UnitTestEx/Assertors/HttpResponseMessageAssertor.cs index c2e6748..946e581 100644 --- a/src/UnitTestEx/Assertors/HttpResponseMessageAssertor.cs +++ b/src/UnitTestEx/Assertors/HttpResponseMessageAssertor.cs @@ -2,6 +2,7 @@ using Microsoft.Net.Http.Headers; using System; +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Mime; @@ -13,8 +14,9 @@ namespace UnitTestEx.Assertors /// Represents the test assert helper. /// /// The owning . + /// The log messages captured during execution. /// The . - public class HttpResponseMessageAssertor(TesterBase owner, HttpResponseMessage response) : HttpResponseMessageAssertorBase(owner, response) + public class HttpResponseMessageAssertor(TesterBase owner, IEnumerable? logs, HttpResponseMessage response) : HttpResponseMessageAssertorBase(owner, logs, response) { /// /// Asserts the the matches the . diff --git a/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBase.cs b/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBase.cs index d2c233f..15bbf1c 100644 --- a/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBase.cs +++ b/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBase.cs @@ -1,6 +1,7 @@ // Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/UnitTestEx using System; +using System.Collections.Generic; using System.Net.Http; using System.Net.Mime; using UnitTestEx.Abstractions; @@ -15,14 +16,20 @@ namespace UnitTestEx.Assertors /// Initializes a new instance of the class. /// /// The owning . + /// The log messages captured during execution. /// The . - public abstract class HttpResponseMessageAssertorBase(TesterBase owner, HttpResponseMessage response) + public abstract class HttpResponseMessageAssertorBase(TesterBase owner, IEnumerable? logs, HttpResponseMessage response) { /// /// Gets the owning . /// public TesterBase Owner { get; } = owner ?? throw new ArgumentNullException(nameof(owner)); + /// + /// Gets the log messages captured during execution. + /// + public IEnumerable LogMessages { get; } = logs ?? []; + /// /// Gets the . /// diff --git a/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBaseT.cs b/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBaseT.cs index 0f47bb6..1c54f2b 100644 --- a/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBaseT.cs +++ b/src/UnitTestEx/Assertors/HttpResponseMessageAssertorBaseT.cs @@ -17,8 +17,9 @@ namespace UnitTestEx.Assertors /// Provides the base test assert helper capabilities. /// /// The owning . + /// The log messages captured during execution. /// The . - public abstract class HttpResponseMessageAssertorBase(TesterBase owner, HttpResponseMessage response) : HttpResponseMessageAssertorBase(owner, response) where TSelf : HttpResponseMessageAssertorBase + public abstract class HttpResponseMessageAssertorBase(TesterBase owner, IEnumerable? logs, HttpResponseMessage response) : HttpResponseMessageAssertorBase(owner, logs, response) where TSelf : HttpResponseMessageAssertorBase { /// /// Asserts that the has a successful value between 200 and 299. diff --git a/src/UnitTestEx/Assertors/HttpResponseMessageAssertorT.cs b/src/UnitTestEx/Assertors/HttpResponseMessageAssertorT.cs index cbb4e26..60e307f 100644 --- a/src/UnitTestEx/Assertors/HttpResponseMessageAssertorT.cs +++ b/src/UnitTestEx/Assertors/HttpResponseMessageAssertorT.cs @@ -2,6 +2,7 @@ using Microsoft.Net.Http.Headers; using System; +using System.Collections.Generic; using System.Net.Http; using UnitTestEx.Abstractions; @@ -11,8 +12,9 @@ namespace UnitTestEx.Assertors /// Represents the test assert helper with a specified response . /// /// The owning . + /// The log messages captured during execution. /// The . - public class HttpResponseMessageAssertor(TesterBase owner, HttpResponseMessage response) : HttpResponseMessageAssertorBase>(owner, response) + public class HttpResponseMessageAssertor(TesterBase owner, IEnumerable? logs, HttpResponseMessage response) : HttpResponseMessageAssertorBase>(owner, logs, response) { private TValue? _value; private bool _valueIsDeserialized; @@ -21,9 +23,10 @@ public class HttpResponseMessageAssertor(TesterBase owner, HttpResponseM /// Initializes a new instance of the class. /// /// The owning . + /// The log messages captured during execution. /// The value already deserialized. /// The . - public HttpResponseMessageAssertor(TesterBase owner, TValue value, HttpResponseMessage response) : this(owner, response) + public HttpResponseMessageAssertor(TesterBase owner, IEnumerable? logs, TValue value, HttpResponseMessage response) : this(owner, logs, response) { _value = value; _valueIsDeserialized = true; @@ -33,7 +36,7 @@ public HttpResponseMessageAssertor(TesterBase owner, TValue value, HttpResponseM /// Initializes a new instance of the class. /// /// The untyped . - internal HttpResponseMessageAssertor(HttpResponseMessageAssertor assertor) : this(assertor.Owner, assertor.Response) { } + internal HttpResponseMessageAssertor(HttpResponseMessageAssertor assertor) : this(assertor.Owner, assertor.LogMessages, assertor.Response) { } /// /// Gets the response content as the deserialized JSON value. diff --git a/src/UnitTestEx/Assertors/HttpResultAssertor.cs b/src/UnitTestEx/Assertors/HttpResultAssertor.cs index fed3b84..a7df407 100644 --- a/src/UnitTestEx/Assertors/HttpResultAssertor.cs +++ b/src/UnitTestEx/Assertors/HttpResultAssertor.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Http; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net.Http; @@ -16,8 +17,9 @@ namespace UnitTestEx.Assertors /// /// The owning . /// The . + /// The logs captured during execution. /// The (if any). - public class HttpResultAssertor(TesterBase owner, IResult result, Exception? exception) : AssertorBase(owner, exception) + public class HttpResultAssertor(TesterBase owner, IResult result, IEnumerable? logs, Exception? exception) : AssertorBase(owner, logs, exception) { /// /// Gets the . @@ -29,16 +31,17 @@ public class HttpResultAssertor(TesterBase owner, IResult result, Exception? exc /// /// The optional requesting with ; otherwise, will default. /// The corresponding . - public HttpResponseMessageAssertor ToHttpResponseMessageAssertor(HttpRequest? httpRequest = null) => ToHttpResponseMessageAssertor(Owner, Result, httpRequest); + public HttpResponseMessageAssertor ToHttpResponseMessageAssertor(HttpRequest? httpRequest = null) => ToHttpResponseMessageAssertor(Owner, Result, LogMessages, httpRequest); /// /// Converts the to an . /// /// The owning . /// The to convert. - /// The optional requesting ; otherwise, will default. + /// The log messages captured during execution. + /// The optional requesting with ; otherwise, will default. /// The corresponding . - internal static HttpResponseMessageAssertor ToHttpResponseMessageAssertor(TesterBase owner, IResult result, HttpRequest? httpRequest) + internal static HttpResponseMessageAssertor ToHttpResponseMessageAssertor(TesterBase owner, IResult result, IEnumerable? logs, HttpRequest? httpRequest) { var sw = Stopwatch.StartNew(); using var ms = new MemoryStream(); @@ -61,7 +64,7 @@ internal static HttpResponseMessageAssertor ToHttpResponseMessageAssertor(Tester sw.Stop(); owner.LogHttpResponseMessage(hr, sw); - return new HttpResponseMessageAssertor(owner, hr); + return new HttpResponseMessageAssertor(owner, logs, hr); } } } diff --git a/src/UnitTestEx/Assertors/ValueAssertor.cs b/src/UnitTestEx/Assertors/ValueAssertor.cs index 8db53f6..8df8262 100644 --- a/src/UnitTestEx/Assertors/ValueAssertor.cs +++ b/src/UnitTestEx/Assertors/ValueAssertor.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Net.Http; using System.Reflection; @@ -16,8 +17,9 @@ namespace UnitTestEx.Assertors /// The result value . /// The owning . /// The result value. + /// The logs captured during execution. /// The (if any). - public class ValueAssertor(TesterBase owner, TValue value, Exception? exception) : AssertorBase>(owner, exception) + public class ValueAssertor(TesterBase owner, TValue value, IEnumerable? logs, Exception? exception) : AssertorBase>(owner, logs, exception) { /// /// Gets the resulting value. @@ -93,7 +95,7 @@ public ValueAssertor AssertJsonFromResource(string resourceNa public ActionResultAssertor ToActionResultAssertor() { if (typeof(IActionResult).IsAssignableFrom(typeof(TValue))) - return new ActionResultAssertor(Owner, (IActionResult)Value!, Exception); + return new ActionResultAssertor(Owner, (IActionResult)Value!, LogMessages, Exception); throw new InvalidOperationException($"Result Type '{typeof(TValue).Name}' must be assignable from '{nameof(IActionResult)}'"); } @@ -109,13 +111,13 @@ public HttpResponseMessageAssertor ToHttpResponseMessageAssertor(HttpRequest? ht if (Value != null) { if (Value is HttpResponseMessage hrm) - return new HttpResponseMessageAssertor(Owner, hrm); + return new HttpResponseMessageAssertor(Owner, LogMessages, hrm); if (Value is IActionResult ar) - return ActionResultAssertor.ToHttpResponseMessageAssertor(Owner, ar, httpRequest); + return ActionResultAssertor.ToHttpResponseMessageAssertor(Owner, ar, LogMessages, httpRequest); #if NET7_0_OR_GREATER if (Value is IResult ir) - return HttpResultAssertor.ToHttpResponseMessageAssertor(Owner, ir, httpRequest); + return HttpResultAssertor.ToHttpResponseMessageAssertor(Owner, ir, LogMessages, httpRequest); #endif } diff --git a/src/UnitTestEx/Assertors/VoidAssertor.cs b/src/UnitTestEx/Assertors/VoidAssertor.cs index 5bcd6ac..bcd2d4f 100644 --- a/src/UnitTestEx/Assertors/VoidAssertor.cs +++ b/src/UnitTestEx/Assertors/VoidAssertor.cs @@ -1,6 +1,7 @@ // Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/UnitTestEx using System; +using System.Collections.Generic; using UnitTestEx.Abstractions; namespace UnitTestEx.Assertors @@ -9,6 +10,7 @@ namespace UnitTestEx.Assertors /// Represents the test assert helper where there is no return value; i.e. . /// /// The owning . + /// The logs captured during execution. /// The (if any). - public class VoidAssertor(TesterBase owner, Exception? exception) : AssertorBase(owner, exception) { } + public class VoidAssertor(TesterBase owner, IEnumerable? logs, Exception? exception) : AssertorBase(owner, logs, exception) { } } \ No newline at end of file diff --git a/src/UnitTestEx/Generic/GenericTesterBase.cs b/src/UnitTestEx/Generic/GenericTesterBase.cs index f8e2a62..8f0ee4e 100644 --- a/src/UnitTestEx/Generic/GenericTesterBase.cs +++ b/src/UnitTestEx/Generic/GenericTesterBase.cs @@ -270,7 +270,7 @@ public async Task RunAsync(Func function) await ExpectationsArranger.AssertAsync(messages, exception).ConfigureAwait(false); - return new VoidAssertor(this, exception); + return new VoidAssertor(this, messages, exception); } #if NET9_0_OR_GREATER @@ -563,7 +563,7 @@ public async Task> RunAsync(Func> fun await ExpectationsArranger.AssertAsync(messages, exception).ConfigureAwait(false); - return new ValueAssertor(this, value, exception); + return new ValueAssertor(this, value, messages, exception); } #if NET9_0_OR_GREATER diff --git a/src/UnitTestEx/Generic/GenericTesterBaseT.cs b/src/UnitTestEx/Generic/GenericTesterBaseT.cs index 3a52b35..a9a17d6 100644 --- a/src/UnitTestEx/Generic/GenericTesterBaseT.cs +++ b/src/UnitTestEx/Generic/GenericTesterBaseT.cs @@ -146,7 +146,7 @@ public async Task> RunAsync(Func> function) await ExpectationsArranger.AssertAsync(messages, exception).ConfigureAwait(false); - return new ValueAssertor(this, value, exception); + return new ValueAssertor(this, value, messages, exception); } } } \ No newline at end of file diff --git a/src/UnitTestEx/Hosting/ScopedTypeTester.cs b/src/UnitTestEx/Hosting/ScopedTypeTester.cs index 7519419..f10bb1d 100644 --- a/src/UnitTestEx/Hosting/ScopedTypeTester.cs +++ b/src/UnitTestEx/Hosting/ScopedTypeTester.cs @@ -134,7 +134,7 @@ public async Task RunAsync(Func function, TesterAr if (!args.BypassRunActions) Owner.ExecutePostRunAfterExpectationsActions(this); - return new VoidAssertor(Owner, ex); + return new VoidAssertor(Owner, logs, ex); } finally { @@ -248,7 +248,7 @@ public async Task> RunAsync(Func(Owner, result, ex); + return new ValueAssertor(Owner, result, logs, ex); } finally { diff --git a/src/UnitTestEx/Hosting/TypeTester.cs b/src/UnitTestEx/Hosting/TypeTester.cs index 8b7af1b..a3763c9 100644 --- a/src/UnitTestEx/Hosting/TypeTester.cs +++ b/src/UnitTestEx/Hosting/TypeTester.cs @@ -137,7 +137,7 @@ public async Task RunAsync(Func function) await ExpectationsArranger.AssertAsync(logs, ex).ConfigureAwait(false); - return new VoidAssertor(Owner, ex); + return new VoidAssertor(Owner, logs, ex); } #if NET9_0_OR_GREATER @@ -229,7 +229,7 @@ public async Task> RunAsync(Func(Owner, result, ex); + return new ValueAssertor(Owner, result, logs, ex); } #if NET9_0_OR_GREATER diff --git a/tests/UnitTestEx.NUnit.Test/PersonControllerTest.cs b/tests/UnitTestEx.NUnit.Test/PersonControllerTest.cs index 61f4784..7540548 100644 --- a/tests/UnitTestEx.NUnit.Test/PersonControllerTest.cs +++ b/tests/UnitTestEx.NUnit.Test/PersonControllerTest.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using NUnit.Framework; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using UnitTestEx.Api; @@ -196,21 +197,28 @@ public void Update_Test6() public void Update_Test7_ExpectationFailure2() { using var test = ApiTester.Create(); - test.Controller() + var assertor = test.Controller() .ExpectStatusCode(System.Net.HttpStatusCode.BadRequest) .ExpectError("No can do eighty-eight.") .Run(c => c.Update(88, new Person { FirstName = null, LastName = null })); + + Assert.That(assertor, Is.Not.Null); + Assert.That(assertor.LogMessages, Is.Not.Null); } [Test] public async Task Http_Get1() { using var test = ApiTester.Create(); - (await test.Http() + var assertor = (await test.Http() .ExpectLogContains("Get using identifier 1") .RunAsync(HttpMethod.Get, "Person/1" )) .AssertOK() .AssertValue(new Person { Id = 1, FirstName = "Bob", LastName = "Smith" }); + + Assert.That(assertor, Is.Not.Null); + Assert.That(assertor.LogMessages, Is.Not.Null); + Assert.That(assertor.LogMessages.Count(m => m.Contains("Get using identifier 1")), Is.EqualTo(1), "Expected log message was not found exactly once."); } [Test] @@ -318,10 +326,13 @@ public void Type_IActionResult() var iar = new OkResult(); - new Assertors.ValueAssertor(test, iar, null) + var valueAssertor = new Assertors.ValueAssertor(test, iar, [], null) .ToHttpResponseMessageAssertor(hr) .AssertNamedHeader("X-Test", "Test") .AssertNoNamedHeader("X-Absent"); + + Assert.That(valueAssertor, Is.Not.Null); + Assert.That(valueAssertor.LogMessages, Is.Not.Null); } } } \ No newline at end of file diff --git a/tests/UnitTestEx.NUnit.Test/ProductFunctionTest.cs b/tests/UnitTestEx.NUnit.Test/ProductFunctionTest.cs index 2e03094..aff8b1b 100644 --- a/tests/UnitTestEx.NUnit.Test/ProductFunctionTest.cs +++ b/tests/UnitTestEx.NUnit.Test/ProductFunctionTest.cs @@ -3,6 +3,7 @@ using Moq; using NUnit.Framework; using System; +using System.Linq; using System.Net; using System.Net.Http; using UnitTestEx.Expectations; @@ -35,12 +36,14 @@ public void Success() .Request(HttpMethod.Get, "products/abc").Respond.WithJson(new { id = "Abc", description = "A blue carrot" }); using var test = FunctionTester.Create(); - test.ReplaceHttpClientFactory(mcf) + var assertor =test.ReplaceHttpClientFactory(mcf) .HttpTrigger() .ExpectLogContains("C# HTTP trigger function processed a request.") .Run(f => f.Run(test.CreateHttpRequest(HttpMethod.Get, "product/abc"), "abc", test.Logger)) .AssertOK() .AssertValue(new { id = "Abc", description = "A blue carrot" }); + + Assert.That(assertor.LogMessages.Count(m => m.Contains("C# HTTP trigger function processed a request.")), Is.EqualTo(1), "Expected log message was not found exactly once."); } [Test] From 03e779c236387a2ebb4c11a166f802ea27916227 Mon Sep 17 00:00:00 2001 From: "Eric Sibly [chullybun]" Date: Thu, 14 May 2026 08:15:39 -0700 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Eric Sibly [chullybun] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5159701..48b72f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ Represents the **NuGet** versions. ## v5.11.0 -- *Enhancement:* Added `AssertorBase.Logs` to enable access to the logs captured during execution of the test for assertion purposes. This is intended to be used in conjunction with the existing `ExpectLogContains` expectation to enable additional (more advanced) assertions against the logs. +- *Enhancement:* Added `AssertorBase.LogMessages` to enable access to the logs captured during execution of the test for assertion purposes. This is intended to be used in conjunction with the existing `ExpectLogContains` expectation to enable additional (more advanced) assertions against the logs. ## v5.10.0 - *Enhancement:* `TestSharedState` updated to enable request-based (isolated) state; with the corresponding `GetHttpRequestId()` method now made public.