From 747cec79145019eaa86cc226490cf91298532a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 1 Feb 2026 06:53:14 +0100 Subject: [PATCH 1/2] docs: document repeating callback invocations (`For`) --- .../02-advanced-callback-features.md | 45 +++++++++++++++---- README.md | 45 +++++++++++++++---- 2 files changed, 72 insertions(+), 18 deletions(-) diff --git a/Docs/pages/advanced-features/02-advanced-callback-features.md b/Docs/pages/advanced-features/02-advanced-callback-features.md index f714d5a4..c5a0a43f 100644 --- a/Docs/pages/advanced-features/02-advanced-callback-features.md +++ b/Docs/pages/advanced-features/02-advanced-callback-features.md @@ -1,29 +1,53 @@ # Advanced callback features -## Conditional callbacks +## Conditional callbacks (`When`) Execute callbacks conditionally based on the zero-based invocation counter using `.When()`: ```csharp sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) - .Do(() => Console.WriteLine("Called!")) - .When(count => count >= 2); // The first two calls are skipped + .Do(() => Console.WriteLine("Called!")).When(count => count >= 2); // The first two calls are skipped ``` -## Frequency control +## Limit invocations (`Only`) -Control how many times a callback executes: +Control after how many times a callback should no longer be executed: ```csharp // Execute up to 3 times sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) - .Do(() => Console.WriteLine("Up to 3 times")) - .Only(3); + .Do(() => Console.WriteLine("Up to 3 times")).Only(3); // Executes the callback only once +sut.SetupMock.Property.TotalDispensed + .Throws(new Exception("This exception is thrown only once")).OnlyOnce(); +``` + +## Repeat invocations (`For`) + +Control how many times a callback should be repeated: + +```csharp sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) - .Do(() => Console.WriteLine("Only once")) - .OnlyOnce(); + .Do(() => Console.WriteLine("First three times")).For(3) + .Do(() => Console.WriteLine("Next three times")).For(3); + +sut.SetupMock.Property.TotalDispensed + .Returns(10).For(1) + .Returns(20).For(2) + .Returns(30).For(3); +// Reads: 10, 20, 20, 30, 30, 30, 0, 0, 0, 0 … +``` + +### Repeat `Forever` + +If you have a sequence of callbacks, you can mark the last one to repeat indefinitely using `.Forever()` to avoid +repeating the sequence from start: + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Returns(true).For(2) // Returns true the first two times + .Returns(false).Forever(); // Then always returns false ``` ## Parallel callbacks @@ -38,6 +62,9 @@ sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) .Do(() => { Console.WriteLine("Runs every other iteration"); }); ``` +**Note:** +This only applies to callbacks defined via `Do`, not to the other setup callbacks like `Returns` or `Throws`. + ## Invocation counter Access the zero-based invocation counter in callbacks: diff --git a/README.md b/README.md index 8ae3dde8..e3957339 100644 --- a/README.md +++ b/README.md @@ -819,30 +819,54 @@ sut.VerifyMock.SetProtectedIndexer(It.Is(0), It.Is(42)).Once(); ### Advanced callback features -#### Conditional callbacks +#### Conditional callbacks (`When`) Execute callbacks conditionally based on the zero-based invocation counter using `.When()`: ```csharp sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) - .Do(() => Console.WriteLine("Called!")) - .When(count => count >= 2); // The first two calls are skipped + .Do(() => Console.WriteLine("Called!")).When(count => count >= 2); // The first two calls are skipped ``` -#### Frequency control +#### Limit invocations (`Only`) -Control how many times a callback executes: +Control after how many times a callback should no longer be executed: ```csharp // Execute up to 3 times sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) - .Do(() => Console.WriteLine("Up to 3 times")) - .Only(3); + .Do(() => Console.WriteLine("Up to 3 times")).Only(3); // Executes the callback only once +sut.SetupMock.Property.TotalDispensed + .Throws(new Exception("This exception is thrown only once")).OnlyOnce(); +``` + +#### Repeat invocations (`For`) + +Control how many times a callback should be repeated: + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("First three times")).For(3) + .Do(() => Console.WriteLine("Next three times")).For(3); + +sut.SetupMock.Property.TotalDispensed + .Returns(10).For(1) + .Returns(20).For(2) + .Returns(30).For(3); +// Reads: 10, 20, 20, 30, 30, 30, 0, 0, 0, 0 … +``` + +**Repeat `Forever`** + +If you have a sequence of callbacks, you can mark the last one to repeat indefinitely using `.Forever()` to avoid +repeating the sequence from start: + +```csharp sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) - .Do(() => Console.WriteLine("Only once")) - .OnlyOnce(); + .Returns(true).For(2) // Returns true the first two times + .Returns(false).Forever(); // Then always returns false ``` #### Parallel callbacks @@ -857,6 +881,9 @@ sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) .Do(() => { Console.WriteLine("Runs every other iteration"); }); ``` +**Note:** +This only applies to callbacks defined via `Do`, not to the other setup callbacks like `Returns` or `Throws`. + #### Invocation counter Access the zero-based invocation counter in callbacks: From 656bd3bc92602213844a99db06c81c502b27fde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 1 Feb 2026 06:57:43 +0100 Subject: [PATCH 2/2] Implement review issues --- Docs/pages/advanced-features/02-advanced-callback-features.md | 3 ++- README.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Docs/pages/advanced-features/02-advanced-callback-features.md b/Docs/pages/advanced-features/02-advanced-callback-features.md index c5a0a43f..6a996063 100644 --- a/Docs/pages/advanced-features/02-advanced-callback-features.md +++ b/Docs/pages/advanced-features/02-advanced-callback-features.md @@ -63,7 +63,8 @@ sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) ``` **Note:** -This only applies to callbacks defined via `Do`, not to the other setup callbacks like `Returns` or `Throws`. +Parallel execution via `.InParallel()` only applies to callbacks defined via `Do`, not to other setup callbacks like +`Returns` or `Throws`. ## Invocation counter diff --git a/README.md b/README.md index e3957339..cacc97c4 100644 --- a/README.md +++ b/README.md @@ -882,7 +882,8 @@ sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) ``` **Note:** -This only applies to callbacks defined via `Do`, not to the other setup callbacks like `Returns` or `Throws`. +Parallel execution via `.InParallel()` only applies to callbacks defined via `Do`, not to other setup callbacks like +`Returns` or `Throws`. #### Invocation counter