diff --git a/Docs/pages/setup/01-properties.md b/Docs/pages/setup/01-properties.md index 55b5017b..ef8023d5 100644 --- a/Docs/pages/setup/01-properties.md +++ b/Docs/pages/setup/01-properties.md @@ -11,9 +11,18 @@ value): sut.SetupMock.Property.TotalDispensed.InitializeWith(42); ``` +You can also register a setup without providing a value (useful when `ThrowWhenNotSetup` is enabled): + +```csharp +var strictMock = Mock.Create(MockBehavior.Default.ThrowingWhenNotSetup()); + +// Register property without value - won't throw +strictMock.SetupMock.Property.TotalDispensed.Register(); +``` + ## Returns / Throws -Alternatively, set up properties with `Returns` and `Throws` (supports sequences): +Set up properties with `Returns` and `Throws` (supports sequences): ```csharp sut.SetupMock.Property.TotalDispensed @@ -23,11 +32,49 @@ sut.SetupMock.Property.TotalDispensed .Returns(4); ``` +You can also return a value based on the previous value: + +```csharp +sut.SetupMock.Property.TotalDispensed + .Returns(current => current + 10); // Increment by 10 each read +``` + ## Callbacks Register callbacks on the setter or getter: ```csharp -sut.SetupMock.Property.TotalDispensed.OnGet.Do(() => Console.WriteLine("TotalDispensed was read!")); -sut.SetupMock.Property.TotalDispensed.OnSet.Do((oldValue, newValue) => Console.WriteLine($"Changed from {oldValue} to {newValue}!") ); +sut.SetupMock.Property.TotalDispensed.OnGet + .Do(() => Console.WriteLine("TotalDispensed was read!")); +sut.SetupMock.Property.TotalDispensed.OnSet + .Do(newValue => Console.WriteLine($"Changed to {newValue}!") ); ``` + +Callbacks can also receive the current value: + +```csharp +// Getter with the current value +sut.SetupMock.Property.TotalDispensed + .OnGet.Do(value => + Console.WriteLine($"Read TotalDispensed current value: {value}")); + +// Setter with the new value +sut.SetupMock.Property.TotalDispensed + .OnSet.Do(newValue => + Console.WriteLine($"Set TotalDispensed to {newValue}")); +``` + +Callbacks also support sequences, similar to `Returns` and `Throws`: + +```csharp +sut.SetupMock.Property.TotalDispensed.OnGet + .Do(() => Console.WriteLine("Execute on all even read interactions")) + .Do(() => Console.WriteLine("Execute on all odd read interactions")); +``` + +**Notes:** + +- All callbacks support more advanced features like conditional execution, frequency control, parallel execution, and + access to the invocation counter. + See [Advanced callback features](https://awexpect.com/docs/mockolate/advanced-features/advanced-callback-features) + for details. diff --git a/Docs/pages/setup/03-indexers.md b/Docs/pages/setup/03-indexers.md index 8fe95e5a..fbf9d7ec 100644 --- a/Docs/pages/setup/03-indexers.md +++ b/Docs/pages/setup/03-indexers.md @@ -12,16 +12,74 @@ sut.SetupMock.Indexer(It.Is("Dark")) .OnSet.Do((value, type) => Console.WriteLine($"Set [{type}] to {value}")); ``` -- `.InitializeWith(…)` can take a value or a callback with parameters. -- `.Returns(…)` and `.Throws(…)` support direct values, callbacks, and callbacks with parameters and/or the current - value. -- `.OnGet.Do(…)` and `.OnSet.Do(…)` support callbacks with or without parameters. -- `.Returns(…)` and `.Throws(…)` can be chained to define a sequence of behaviors, which are cycled through on each - call. +## Initialization + +You can initialize indexers so they work like normal indexers (setter changes the value, getter returns the last set +value): + +```csharp +sut.SetupMock.Indexer(It.IsAny()).InitializeWith(42); +``` + +## Returns / Throws + +Set up indexers with `Returns` and `Throws` (supports sequences): + +```csharp +sut.SetupMock.Indexer(It.IsAny()) + .Returns(1) + .Returns(2) + .Throws(new Exception("Error")) + .Returns(4); +``` + +You can also return a value based on the previous value: + +```csharp +sut.SetupMock.Indexer(It.IsAny()) + .Returns(current => current + 10); // Increment by 10 each read +``` + +## Callbacks + +Register callbacks on the setter or getter of the indexer: + +```csharp +sut.SetupMock.Indexer(It.IsAny()).OnGet + .Do(() => Console.WriteLine("Indexer was read!")); +sut.SetupMock.Indexer(It.IsAny()).OnSet + .Do(newValue => Console.WriteLine($"Changed indexer to {newValue}!") ); +``` + +Callbacks can also receive the indexer parameters and the current value: + +```csharp +// Getter with the current value +sut.SetupMock.Indexer(It.IsAny()) + .OnGet.Do((string index, int value) => + Console.WriteLine($"Read this[{index}] current value: {value}")); + +// Setter with the new value +sut.SetupMock.Indexer(It.IsAny()) + .OnSet.Do((string index, int newValue) => + Console.WriteLine($"Set this[{index}] to {newValue}")); +``` + +Callbacks also support sequences, similar to `Returns` and `Throws`: + +```csharp +sut.SetupMock.Indexer(It.IsAny()).OnGet + .Do(() => Console.WriteLine("Execute on all even read interactions")) + .Do(() => Console.WriteLine("Execute on all odd read interactions")); +``` + +**Notes:** +- All callbacks support more advanced features like conditional execution, frequency control, parallel execution, and + access to the invocation counter. + See [Advanced callback features](https://awexpect.com/docs/mockolate/advanced-features/advanced-callback-features) for + details. +- You can use the same [parameter matching](https://awexpect.com/docs/mockolate/setup/parameter-matching) + and [interaction](https://awexpect.com/docs/mockolate/setup/parameter-matching#parameter-interaction) options as for + methods. - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific indexer (only for class mocks). - When you specify overlapping setups, the most recently defined setup takes precedence. - -**Note**: -You can use the same [parameter matching](https://awexpect.com/docs/mockolate/setup/parameter-matching) -and [interaction](https://awexpect.com/docs/mockolate/setup/parameter-matching#parameter-interaction) options as for -methods. diff --git a/README.md b/README.md index 7053a80b..87a03347 100644 --- a/README.md +++ b/README.md @@ -206,9 +206,18 @@ value): sut.SetupMock.Property.TotalDispensed.InitializeWith(42); ``` +You can also register a setup without providing a value (useful when `ThrowWhenNotSetup` is enabled): + +```csharp +var strictMock = Mock.Create(MockBehavior.Default.ThrowingWhenNotSetup()); + +// Register property without value - won't throw +strictMock.SetupMock.Property.TotalDispensed.Register(); +``` + **Returns / Throws** -Alternatively, set up properties with `Returns` and `Throws` (supports sequences): +Set up properties with `Returns` and `Throws` (supports sequences): ```csharp sut.SetupMock.Property.TotalDispensed @@ -218,15 +227,52 @@ sut.SetupMock.Property.TotalDispensed .Returns(4); ``` +You can also return a value based on the previous value: + +```csharp +sut.SetupMock.Property.TotalDispensed + .Returns(current => current + 10); // Increment by 10 each read +``` + **Callbacks** Register callbacks on the setter or getter: ```csharp -sut.SetupMock.Property.TotalDispensed.OnGet.Do(() => Console.WriteLine("TotalDispensed was read!")); -sut.SetupMock.Property.TotalDispensed.OnSet.Do((oldValue, newValue) => Console.WriteLine($"Changed from {oldValue} to {newValue}!") ); +sut.SetupMock.Property.TotalDispensed.OnGet + .Do(() => Console.WriteLine("TotalDispensed was read!")); +sut.SetupMock.Property.TotalDispensed.OnSet + .Do(newValue => Console.WriteLine($"Changed to {newValue}!") ); +``` + +Callbacks can also receive the current value: + +```csharp +// Getter with the current value +sut.SetupMock.Property.TotalDispensed + .OnGet.Do(value => + Console.WriteLine($"Read TotalDispensed current value: {value}")); + +// Setter with the new value +sut.SetupMock.Property.TotalDispensed + .OnSet.Do(newValue => + Console.WriteLine($"Set TotalDispensed to {newValue}")); +``` + +Callbacks also support sequences, similar to `Returns` and `Throws`: + +```csharp +sut.SetupMock.Property.TotalDispensed.OnGet + .Do(() => Console.WriteLine("Execute on all even read interactions")) + .Do(() => Console.WriteLine("Execute on all odd read interactions")); ``` +*Notes:* + +- All callbacks support more advanced features like conditional execution, frequency control, parallel execution, and + access to the invocation counter. + See [Advanced callback features](#advanced-callback-features) for details. + ### Methods Use `mock.SetupMock.Method.MethodName(…)` to set up methods. You can specify argument matchers for each parameter. @@ -290,19 +336,79 @@ sut.SetupMock.Indexer(It.Is("Dark")) .OnSet.Do((value, type) => Console.WriteLine($"Set [{type}] to {value}")); ``` -- `.InitializeWith(…)` can take a value or a callback with parameters. -- `.Returns(…)` and `.Throws(…)` support direct values, callbacks, and callbacks with parameters and/or the current - value. -- `.OnGet.Do(…)` and `.OnSet.Do(…)` support callbacks with or without parameters. -- `.Returns(…)` and `.Throws(…)` can be chained to define a sequence of behaviors, which are cycled through on each - call. +**Initialization** + +You can initialize indexers so they work like normal indexers (setter changes the value, getter returns the last set +value): + +```csharp +sut.SetupMock.Indexer(It.IsAny()).InitializeWith(42); +``` + +**Returns / Throws** + +Set up indexers with `Returns` and `Throws` (supports sequences): + +```csharp +sut.SetupMock.Indexer(It.IsAny()) + .Returns(1) + .Returns(2) + .Throws(new Exception("Error")) + .Returns(4); +``` + +You can also return a value based on the previous value: + +```csharp +sut.SetupMock.Indexer(It.IsAny()) + .Returns(current => current + 10); // Increment by 10 each read +``` + +**Callbacks** + +Register callbacks on the setter or getter of the indexer: + +```csharp +sut.SetupMock.Indexer(It.IsAny()).OnGet + .Do(() => Console.WriteLine("Indexer was read!")); +sut.SetupMock.Indexer(It.IsAny()).OnSet + .Do(newValue => Console.WriteLine($"Changed indexer to {newValue}!") ); +``` + +Callbacks can also receive the indexer parameters and the current value: + +```csharp +// Getter with the current value +sut.SetupMock.Indexer(It.IsAny()) + .OnGet.Do((string index, int value) => + Console.WriteLine($"Read this[{index}] current value: {value}")); + +// Setter with the new value +sut.SetupMock.Indexer(It.IsAny()) + .OnSet.Do((string index, int newValue) => + Console.WriteLine($"Set this[{index}] to {newValue}")); +``` + +Callbacks also support sequences, similar to `Returns` and `Throws`: + +```csharp +sut.SetupMock.Indexer(It.IsAny()).OnGet + .Do(() => Console.WriteLine("Execute on all even read interactions")) + .Do(() => Console.WriteLine("Execute on all odd read interactions")); +``` + +**Notes:** + +- All callbacks support more advanced features like conditional execution, frequency control, parallel execution, and + access to the invocation counter. + See [Advanced callback features](#advanced-callback-features) for + details. +- You can use the same [parameter matching](#parameter-matching) + and [interaction](#parameter-interaction) options as for + methods. - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific indexer (only for class mocks). - When you specify overlapping setups, the most recently defined setup takes precedence. -**Note**: -You can use the same [parameter matching](#parameter-matching) and [interaction](#parameter-interaction) options as for -methods. - ### Parameter Matching Mockolate provides flexible parameter matching for method setups and verifications: