From 77bf3d470f15fe72a9b8aa084fd6dd30dc5fee6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 17:31:02 +0000 Subject: [PATCH 1/3] Initial plan From 314d04ad763d84449573290781b7424a6d8c0918 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 17:33:01 +0000 Subject: [PATCH 2/3] Add documentation for protected member support Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com> --- Docs/pages/02-setup.md | 36 +++++++++++++++++ Docs/pages/04-verify-interactions.md | 25 ++++++++++++ README.md | 60 ++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/Docs/pages/02-setup.md b/Docs/pages/02-setup.md index 0fd64d46..da5d2c25 100644 --- a/Docs/pages/02-setup.md +++ b/Docs/pages/02-setup.md @@ -161,3 +161,39 @@ sut.SetupMock.Indexer(It.Is("Dark")) **Note**: You can use the same [parameter matching](#parameter-matching) and [interaction](#parameter-interaction) options as for methods. + +## Working with Protected Members + +Mockolate allows you to setup and verify protected methods and properties on class mocks. Access protected members using the `.Protected` property: + +```csharp +public abstract class ChocolateDispenser +{ + protected virtual bool DispenseInternal(string type, int amount) => true; + protected virtual int InternalStock { get; set; } +} + +var sut = Mock.Create(); + +// Setup protected method +sut.SetupMock.Protected.Method.DispenseInternal( + It.Is("Dark"), It.IsAny()) + .Returns(true); + +// Setup protected property +sut.SetupMock.Protected.Property.InternalStock.InitializeWith(100); + +// Verify protected method was called +sut.VerifyMock.Invoked.Protected.DispenseInternal( + It.Is("Dark"), It.IsAny()).Once(); + +// Verify protected property was accessed +sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); +``` + +**Notes:** +- Protected members can be set up and verified just like public members, using the `.Protected` accessor. +- All setup options (`.Returns()`, `.Throws()`, `.Do()`, `.InitializeWith()`, etc.) work with protected members. +- All verification options (`.Once()`, `.AtLeastOnce()`, etc.) work with protected members. +- Protected indexers are supported using `.Protected.Indexer()` for setup and `.GotProtectedIndexer()`/`.SetProtectedIndexer()` for verification. + diff --git a/Docs/pages/04-verify-interactions.md b/Docs/pages/04-verify-interactions.md index ba095886..7dae79e9 100644 --- a/Docs/pages/04-verify-interactions.md +++ b/Docs/pages/04-verify-interactions.md @@ -99,6 +99,31 @@ sut.VerifyMock.SubscribedTo.ChocolateDispensed().AtLeastOnce(); sut.VerifyMock.UnsubscribedFrom.ChocolateDispensed().Once(); ``` +## Protected Members + +You can verify interactions with protected members on class mocks using the `.Protected` accessor: + +```csharp +// Verify protected method was invoked +sut.VerifyMock.Invoked.Protected.DispenseInternal( + It.Is("Dark"), It.IsAny()).Once(); + +// Verify protected property was read +sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); + +// Verify protected property was set +sut.VerifyMock.Set.Protected.InternalStock(It.Is(100)).Once(); + +// Verify protected indexer was read +sut.VerifyMock.GotProtectedIndexer(It.Is(0)).Once(); + +// Verify protected indexer was set +sut.VerifyMock.SetProtectedIndexer(It.Is(0), It.Is(42)).Once(); +``` + +**Note:** +All verification options (argument matchers, count assertions) work the same for protected members as for public members. + ## Call Ordering Use `Then` to verify that calls occurred in a specific order: diff --git a/README.md b/README.md index 183d0a8e..af5d0e2e 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,41 @@ sut.SetupMock.Indexer(It.Is("Dark")) You can use the same [parameter matching](#parameter-matching) and [interaction](#parameter-interaction) options as for methods. +### Working with Protected Members + +Mockolate allows you to setup and verify protected methods and properties on class mocks. Access protected members using the `.Protected` property: + +```csharp +public abstract class ChocolateDispenser +{ + protected virtual bool DispenseInternal(string type, int amount) => true; + protected virtual int InternalStock { get; set; } +} + +var sut = Mock.Create(); + +// Setup protected method +sut.SetupMock.Protected.Method.DispenseInternal( + It.Is("Dark"), It.IsAny()) + .Returns(true); + +// Setup protected property +sut.SetupMock.Protected.Property.InternalStock.InitializeWith(100); + +// Verify protected method was called +sut.VerifyMock.Invoked.Protected.DispenseInternal( + It.Is("Dark"), It.IsAny()).Once(); + +// Verify protected property was accessed +sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); +``` + +**Notes:** +- Protected members can be set up and verified just like public members, using the `.Protected` accessor. +- All setup options (`.Returns()`, `.Throws()`, `.Do()`, `.InitializeWith()`, etc.) work with protected members. +- All verification options (`.Once()`, `.AtLeastOnce()`, etc.) work with protected members. +- Protected indexers are supported using `.Protected.Indexer()` for setup and `.GotProtectedIndexer()`/`.SetProtectedIndexer()` for verification. + ## Mock events Easily raise events on your mock to test event handlers in your code. @@ -453,6 +488,31 @@ sut.VerifyMock.SubscribedTo.ChocolateDispensed().AtLeastOnce(); sut.VerifyMock.UnsubscribedFrom.ChocolateDispensed().Once(); ``` +### Protected Members + +You can verify interactions with protected members on class mocks using the `.Protected` accessor: + +```csharp +// Verify protected method was invoked +sut.VerifyMock.Invoked.Protected.DispenseInternal( + It.Is("Dark"), It.IsAny()).Once(); + +// Verify protected property was read +sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); + +// Verify protected property was set +sut.VerifyMock.Set.Protected.InternalStock(It.Is(100)).Once(); + +// Verify protected indexer was read +sut.VerifyMock.GotProtectedIndexer(It.Is(0)).Once(); + +// Verify protected indexer was set +sut.VerifyMock.SetProtectedIndexer(It.Is(0), It.Is(42)).Once(); +``` + +**Note:** +All verification options (argument matchers, count assertions) work the same for protected members as for public members. + ### Call Ordering Use `Then` to verify that calls occurred in a specific order: From fa64794811a772cfbba76ddd6556dd046067b1d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 17:36:21 +0000 Subject: [PATCH 3/3] Address code review feedback: fix verb form and remove verification examples from setup section Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com> --- Docs/pages/02-setup.md | 10 ++-------- README.md | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Docs/pages/02-setup.md b/Docs/pages/02-setup.md index da5d2c25..90140106 100644 --- a/Docs/pages/02-setup.md +++ b/Docs/pages/02-setup.md @@ -164,7 +164,7 @@ methods. ## Working with Protected Members -Mockolate allows you to setup and verify protected methods and properties on class mocks. Access protected members using the `.Protected` property: +Mockolate allows you to set up and verify protected methods and properties on class mocks. Access protected members using the `.Protected` property: ```csharp public abstract class ChocolateDispenser @@ -182,13 +182,6 @@ sut.SetupMock.Protected.Method.DispenseInternal( // Setup protected property sut.SetupMock.Protected.Property.InternalStock.InitializeWith(100); - -// Verify protected method was called -sut.VerifyMock.Invoked.Protected.DispenseInternal( - It.Is("Dark"), It.IsAny()).Once(); - -// Verify protected property was accessed -sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); ``` **Notes:** @@ -196,4 +189,5 @@ sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); - All setup options (`.Returns()`, `.Throws()`, `.Do()`, `.InitializeWith()`, etc.) work with protected members. - All verification options (`.Once()`, `.AtLeastOnce()`, etc.) work with protected members. - Protected indexers are supported using `.Protected.Indexer()` for setup and `.GotProtectedIndexer()`/`.SetProtectedIndexer()` for verification. +- For verification examples, see the Protected Members section in the verify interactions documentation. diff --git a/README.md b/README.md index af5d0e2e..0130b283 100644 --- a/README.md +++ b/README.md @@ -318,7 +318,7 @@ methods. ### Working with Protected Members -Mockolate allows you to setup and verify protected methods and properties on class mocks. Access protected members using the `.Protected` property: +Mockolate allows you to set up and verify protected methods and properties on class mocks. Access protected members using the `.Protected` property: ```csharp public abstract class ChocolateDispenser @@ -336,13 +336,6 @@ sut.SetupMock.Protected.Method.DispenseInternal( // Setup protected property sut.SetupMock.Protected.Property.InternalStock.InitializeWith(100); - -// Verify protected method was called -sut.VerifyMock.Invoked.Protected.DispenseInternal( - It.Is("Dark"), It.IsAny()).Once(); - -// Verify protected property was accessed -sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); ``` **Notes:** @@ -350,6 +343,7 @@ sut.VerifyMock.Got.Protected.InternalStock().AtLeastOnce(); - All setup options (`.Returns()`, `.Throws()`, `.Do()`, `.InitializeWith()`, etc.) work with protected members. - All verification options (`.Once()`, `.AtLeastOnce()`, etc.) work with protected members. - Protected indexers are supported using `.Protected.Indexer()` for setup and `.GotProtectedIndexer()`/`.SetProtectedIndexer()` for verification. +- See [Protected Members](#protected-members) in the Verify interactions section for verification examples. ## Mock events