From 8357f927bc0c471a70f4d9f3ac283a45226d9dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sat, 28 Feb 2026 21:04:25 +0100 Subject: [PATCH 1/2] docs: document new features - `Within` and `WithCancellation` - verification of method setups - `HttpClient` return extensions --- Docs/pages/04-verify-interactions.md | 24 +++++++++++ Docs/pages/special-types/01-httpclient.md | 28 ++++++++++++ README.md | 52 +++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/Docs/pages/04-verify-interactions.md b/Docs/pages/04-verify-interactions.md index 68581345..9e7c8265 100644 --- a/Docs/pages/04-verify-interactions.md +++ b/Docs/pages/04-verify-interactions.md @@ -18,6 +18,22 @@ Supported call count verifications in the `Mockolate.VerifyMock` namespace: - `.Between(min, max)`: The interaction occurred between min and max times (inclusive) - `.Times(predicate)`: The interaction count matches the predicate +If the invocations run in a background thread, you can use `Within(TimeSpan)` to specify a timeout in which to wait for +the expected interactions to occur: + +```csharp +// Wait up to 1 second for Dispense("Dark", 5) to be invoked +sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.Is(5)) + .Within(TimeSpan.FromSeconds(1)) + .AtLeastOnce(); +``` + +You can also use `WithCancellation(CancellationToken)` to wait for the expected interactions until the cancellation +token is canceled. If you combine this with the `Within` method, both cancellations are respected. + +In both cases, it will block the test execution until the expected interaction occurs or the timeout is reached. +If the interaction does not occur within the specified time, a `MockVerificationException` will be thrown. + ## Properties You can verify access to property getter and setter: @@ -59,6 +75,14 @@ sut.VerifyMock.Invoked.Dispense(It.IsAny(), It.IsAny()) .Times(count => count % 2 == 0); ``` +You can also verify that a specific setup was invoked a specific number of times: + +```csharp +var setup = sut.SetupMock.Method.Dispense(It.Is("Dark"), It.Is(5)).Returns(true); +// Act +sut.VerifyMock.InvokedSetup(setup).AtLeastOnce(); +``` + ## Indexers You can verify access to indexer getter and setter: diff --git a/Docs/pages/special-types/01-httpclient.md b/Docs/pages/special-types/01-httpclient.md index 0d6b0f95..20ab1528 100644 --- a/Docs/pages/special-types/01-httpclient.md +++ b/Docs/pages/special-types/01-httpclient.md @@ -243,3 +243,31 @@ httpClient.SetupMock.Method - By default, only the content headers are checked, not the headers in the corresponding `HttpRequestMessage`. If you want to check both, add the `.IncludingRequestHeaders()` modifier. + +## Return Message + +Overloads of `.ReturnsAsync` simplify specifying the return value for HTTP method setups. + +```csharp +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and no content + .ReturnsAsync(HttpStatusCode.OK); + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a string content "some string content" + .ReturnsAsync(HttpStatusCode.OK, "some string content"); + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a JSON content {"foo":"bar"} + .ReturnsAsync(HttpStatusCode.OK, "{\"foo\":\"bar\"}", "application/json"); + +byte[] bytes = //... some byte array content + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a binary content with the provided bytes + .ReturnsAsync(HttpStatusCode.OK, bytes); + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a PNG image content with the provided bytes + .ReturnsAsync(HttpStatusCode.OK, bytes, "image/png"); +``` diff --git a/README.md b/README.md index 0b50ccd8..5e6b5d0f 100644 --- a/README.md +++ b/README.md @@ -644,6 +644,22 @@ Supported call count verifications in the `Mockolate.VerifyMock` namespace: - `.Between(min, max)`: The interaction occurred between min and max times (inclusive) - `.Times(predicate)`: The interaction count matches the predicate +If the invocations run in a background thread, you can use `Within(TimeSpan)` to specify a timeout in which to wait for +the expected interactions to occur: + +```csharp +// Wait up to 1 second for Dispense("Dark", 5) to be invoked +sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.Is(5)) + .Within(TimeSpan.FromSeconds(1)) + .AtLeastOnce(); +``` + +You can also use `WithCancellation(CancellationToken)` to wait for the expected interactions until the cancellation +token is canceled. If you combine this with the `Within` method, both cancellations are respected. + +In both cases, it will block the test execution until the expected interaction occurs or the timeout is reached. +If the interaction does not occur within the specified time, a `MockVerificationException` will be thrown. + ### Properties You can verify access to property getter and setter: @@ -685,6 +701,14 @@ sut.VerifyMock.Invoked.Dispense(It.IsAny(), It.IsAny()) .Times(count => count % 2 == 0); ``` +You can also verify that a specific setup was invoked a specific number of times: + +```csharp +var setup = sut.SetupMock.Method.Dispense(It.Is("Dark"), It.Is(5)).Returns(true); +// Act +sut.VerifyMock.InvokedSetup(setup).AtLeastOnce(); +``` + ### Indexers You can verify access to indexer getter and setter: @@ -1225,6 +1249,34 @@ httpClient.SetupMock.Method - By default, only the content headers are checked, not the headers in the corresponding `HttpRequestMessage`. If you want to check both, add the `.IncludingRequestHeaders()` modifier. +#### Return Message + +Overloads of `.ReturnsAsync` simplify specifying the return value for HTTP method setups. + +```csharp +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and no content + .ReturnsAsync(HttpStatusCode.OK); + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a string content "some string content" + .ReturnsAsync(HttpStatusCode.OK, "some string content"); + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a JSON content {"foo":"bar"} + .ReturnsAsync(HttpStatusCode.OK, "{\"foo\":\"bar\"}", "application/json"); + +byte[] bytes = //... some byte array content + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a binary content with the provided bytes + .ReturnsAsync(HttpStatusCode.OK, bytes); + +httpClient.SetupMock.Method.GetAsync(It.IsAny()) + // Returns a response with status code 200 OK and a PNG image content with the provided bytes + .ReturnsAsync(HttpStatusCode.OK, bytes, "image/png"); +``` + ### Delegates Mockolate supports mocking delegates including `Action`, `Func`, and custom delegates. From 341fb8af5bc9fe61fbad2cfef9edb650f386a01e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sat, 28 Feb 2026 21:10:19 +0100 Subject: [PATCH 2/2] Fix review issues --- Docs/pages/04-verify-interactions.md | 2 +- Docs/pages/special-types/01-httpclient.md | 2 +- README.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Docs/pages/04-verify-interactions.md b/Docs/pages/04-verify-interactions.md index 9e7c8265..721063f7 100644 --- a/Docs/pages/04-verify-interactions.md +++ b/Docs/pages/04-verify-interactions.md @@ -29,7 +29,7 @@ sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.Is(5)) ``` You can also use `WithCancellation(CancellationToken)` to wait for the expected interactions until the cancellation -token is canceled. If you combine this with the `Within` method, both cancellations are respected. +token is canceled. If you combine this with the `Within` method, both the timeout and the cancellation token are respected. In both cases, it will block the test execution until the expected interaction occurs or the timeout is reached. If the interaction does not occur within the specified time, a `MockVerificationException` will be thrown. diff --git a/Docs/pages/special-types/01-httpclient.md b/Docs/pages/special-types/01-httpclient.md index 20ab1528..16b1a98b 100644 --- a/Docs/pages/special-types/01-httpclient.md +++ b/Docs/pages/special-types/01-httpclient.md @@ -261,7 +261,7 @@ httpClient.SetupMock.Method.GetAsync(It.IsAny()) // Returns a response with status code 200 OK and a JSON content {"foo":"bar"} .ReturnsAsync(HttpStatusCode.OK, "{\"foo\":\"bar\"}", "application/json"); -byte[] bytes = //... some byte array content +byte[] bytes = new byte[] { /* ... */ }; httpClient.SetupMock.Method.GetAsync(It.IsAny()) // Returns a response with status code 200 OK and a binary content with the provided bytes diff --git a/README.md b/README.md index 5e6b5d0f..f6052acb 100644 --- a/README.md +++ b/README.md @@ -655,7 +655,7 @@ sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.Is(5)) ``` You can also use `WithCancellation(CancellationToken)` to wait for the expected interactions until the cancellation -token is canceled. If you combine this with the `Within` method, both cancellations are respected. +token is canceled. If you combine this with the `Within` method, both the timeout and the cancellation token are respected. In both cases, it will block the test execution until the expected interaction occurs or the timeout is reached. If the interaction does not occur within the specified time, a `MockVerificationException` will be thrown. @@ -1266,7 +1266,7 @@ httpClient.SetupMock.Method.GetAsync(It.IsAny()) // Returns a response with status code 200 OK and a JSON content {"foo":"bar"} .ReturnsAsync(HttpStatusCode.OK, "{\"foo\":\"bar\"}", "application/json"); -byte[] bytes = //... some byte array content +byte[] bytes = new byte[] { /* ... */ }; httpClient.SetupMock.Method.GetAsync(It.IsAny()) // Returns a response with status code 200 OK and a binary content with the provided bytes