diff --git a/Docs/pages/02-setup.md b/Docs/pages/02-setup.md index 0fd64d46..81d85322 100644 --- a/Docs/pages/02-setup.md +++ b/Docs/pages/02-setup.md @@ -41,6 +41,57 @@ sut.SetupMock.Method.Dispense(It.Is("Green"), It.IsAny()) - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific method (only for class mocks). - When you specify overlapping setups, the most recently defined setup takes precedence. +#### Advanced Callback Features + +**Conditional Callbacks** + +Execute callbacks conditionally based on invocation count using `.When()`: + +```csharp +sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) + .Do(() => Console.WriteLine("Called!")) + .When(count => count < 3); // Only first 3 invocations (count is 0-indexed) +``` + +**Frequency Control** + +Control how many times a callback executes: + +```csharp +// Execute exactly 5 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("First 5 calls")) + .For(5); + +// Execute up to 3 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("Up to 3 calls")) + .Only(3); +``` + +**Parallel Callbacks** + +Execute callbacks in parallel (all callbacks run on every invocation): + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => { /* parallel work */ }) + .InParallel(); +``` + +**Invocation Counter** + +Access the invocation counter in callbacks: + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do((int count) => Console.WriteLine($"Call #{count}")); + +sut.SetupMock.Property.TotalDispensed + .OnGet.Do((int count, int value) => + Console.WriteLine($"Read #{count}, value: {value}")); +``` + **Async Methods** For `Task` or `ValueTask` methods, use `.ReturnsAsync(…)`: diff --git a/README.md b/README.md index 71a3292f..2784c09d 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,57 @@ sut.SetupMock.Method.Dispense(It.Is("Green"), It.IsAny()) - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific method (only for class mocks). - When you specify overlapping setups, the most recently defined setup takes precedence. +#### Advanced Callback Features + +**Conditional Callbacks** + +Execute callbacks conditionally based on invocation count using `.When()`: + +```csharp +sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) + .Do(() => Console.WriteLine("Called!")) + .When(count => count < 3); // Only first 3 invocations (count is 0-indexed) +``` + +**Frequency Control** + +Control how many times a callback executes: + +```csharp +// Execute exactly 5 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("First 5 calls")) + .For(5); + +// Execute up to 3 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("Up to 3 calls")) + .Only(3); +``` + +**Parallel Callbacks** + +Execute callbacks in parallel (all callbacks run on every invocation): + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => { /* parallel work */ }) + .InParallel(); +``` + +**Invocation Counter** + +Access the invocation counter in callbacks: + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do((int count) => Console.WriteLine($"Call #{count}")); + +sut.SetupMock.Property.TotalDispensed + .OnGet.Do((int count, int value) => + Console.WriteLine($"Read #{count}, value: {value}")); +``` + **Async Methods** For `Task` or `ValueTask` methods, use `.ReturnsAsync(…)`: