From 41098e0cab96621c88c0ded7f21dee5d576a0de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Mon, 31 Aug 2026 19:06:38 +0200 Subject: [PATCH 1/4] docs: describe reaching a mock's other interfaces The "Implementing additional interfaces" section covered `.Implementing()` and `Mock.As()` but left out how they behave in practice. Adds: - the cast accessor `((ILemonadeDispenser)sut).Mock`, which reaches the same surface without the `As()` hop - `Mock.As()` throwing `MockException` for a type the mock does not implement - `Mock.As()` reaching a base interface member the mocked interface hides with `new`, which needs no `.Implementing()` and keeps the two slots apart - what `.Implementing()` does with a class that already implements the interface: members it implements non-virtually are reachable only through the interface slot - that `.Implementing()` returns a new instance, that it carries the constructor parameters over, and that indexers share storage across a `new` Every sample was compiled and run against the generator. --- Docs/pages/01-create-mocks.md | 78 +++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/Docs/pages/01-create-mocks.md b/Docs/pages/01-create-mocks.md index dec13be2..5eb90e74 100644 --- a/Docs/pages/01-create-mocks.md +++ b/Docs/pages/01-create-mocks.md @@ -117,9 +117,87 @@ sut.Mock.As().Verify.DispenseLemonade(5).Once(); The returned mock shares the registry of the original - recorded interactions, scenario state, and setups apply across all faces of the same instance. +Where the mock is already typed as the additional interface, its own `Mock` accessor reaches the same surface, so +the `As()` hop can be skipped: + +```csharp +((ILemonadeDispenser)sut).Mock.Setup.DispenseLemonade(It.IsAny()).Returns(true); +((ILemonadeDispenser)sut).Mock.Verify.DispenseLemonade(5).Once(); +``` + +`Mock.As()` throws a `MockException` when the mock does not implement `T`. + +**Reaching members hidden with `new`** + +`Mock.As()` also reaches a base interface whose members the mocked interface hides with `new`. No +`.Implementing()` is needed here - the base interface is already part of the mocked type - and the two slots stay +separate members, each with its own setups and recorded interactions: + +```csharp +public interface IChocolateShelfBase +{ + int Restock(); +} + +public interface IChocolateShelf : IChocolateShelfBase +{ + new int Restock(); +} + +IChocolateShelf sut = IChocolateShelf.CreateMock(); +sut.Mock.Setup.Restock().Returns(42); +sut.Mock.As().Setup.Restock().Returns(43); + +int viaDerived = sut.Restock(); // 42 +int viaBase = ((IChocolateShelfBase)sut).Restock(); // 43 + +sut.Mock.Verify.Restock().Once(); +sut.Mock.As().Verify.Restock().Once(); +``` + +**When the class already implements the interface** + +`.Implementing()` is also useful when the mocked class itself implements `T`, because it makes members the +class implements non-virtually reachable: + +```csharp +public interface ICalculator +{ + int Add(int a, int b); + int Multiply(int a, int b); +} + +public abstract class Calculator : ICalculator +{ + public int Add(int a, int b) => a + b; // not virtual + public abstract int Multiply(int a, int b); +} + +Calculator sut = Calculator.CreateMock().Implementing(); + +// `Multiply` is overridable, so the class and the interface are one member: +// either surface configures it, and both calls are recorded against it. +sut.Mock.Setup.Multiply(It.IsAny(), It.IsAny()).Returns(7); +int viaClass = sut.Multiply(3, 4); // 7 +int viaInterface = ((ICalculator)sut).Multiply(3, 4); // 7 + +// `Add` is not virtual, so the class call cannot be intercepted - only the interface slot can. +sut.Mock.As().Setup.Add(It.IsAny(), It.IsAny()).Returns(99); +int addViaClass = sut.Add(1, 2); // 3 - the real implementation +int addViaInterface = ((ICalculator)sut).Add(1, 2); // 99 +``` + **Notes:** - Only the first type can be a class; additional types must be interfaces. +- Members the class implements non-virtually are only mockable through the interface; cast the mock (or type + your subject as the interface) to reach them. +- `.Implementing()` returns a new instance rather than modifying the one it was called on. Keep the returned + mock - the original reference does not implement `T`. +- On class mocks, `.Implementing()` reuses the constructor parameters the mock was created with, so + `CreateMock([…])` arguments carry over. +- Indexers are keyed by their parameter signature rather than by the declaring interface, so a `new` indexer and + the base indexer it hides share the same storage. ## Wrapping existing instances From c548f3464761830db3ee95ee0c439bd1651a0286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Mon, 31 Aug 2026 20:44:10 +0200 Subject: [PATCH 2/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Docs/pages/01-create-mocks.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Docs/pages/01-create-mocks.md b/Docs/pages/01-create-mocks.md index 5eb90e74..dd26a511 100644 --- a/Docs/pages/01-create-mocks.md +++ b/Docs/pages/01-create-mocks.md @@ -130,8 +130,7 @@ the `As()` hop can be skipped: **Reaching members hidden with `new`** `Mock.As()` also reaches a base interface whose members the mocked interface hides with `new`. No -`.Implementing()` is needed here - the base interface is already part of the mocked type - and the two slots stay -separate members, each with its own setups and recorded interactions: +`.Implementing()` is needed here - the base interface is already part of the mocked type - and (for methods, properties, and events) the two slots stay separate members, each with its own setups and recorded interactions (indexers are an exception; see Notes below): ```csharp public interface IChocolateShelfBase From e9295c99ea455f629373d16ab08b93ea0c8835fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Mon, 31 Aug 2026 20:57:20 +0200 Subject: [PATCH 3/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Docs/pages/01-create-mocks.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Docs/pages/01-create-mocks.md b/Docs/pages/01-create-mocks.md index dd26a511..5df20ad7 100644 --- a/Docs/pages/01-create-mocks.md +++ b/Docs/pages/01-create-mocks.md @@ -130,8 +130,9 @@ the `As()` hop can be skipped: **Reaching members hidden with `new`** `Mock.As()` also reaches a base interface whose members the mocked interface hides with `new`. No -`.Implementing()` is needed here - the base interface is already part of the mocked type - and (for methods, properties, and events) the two slots stay separate members, each with its own setups and recorded interactions (indexers are an exception; see Notes below): - +`.Implementing()` is needed here - the base interface is already part of the mocked type - and (for methods, +properties, and events) the two slots stay separate members, each with its own setups and recorded interactions +(indexers are an exception; see Notes below): ```csharp public interface IChocolateShelfBase { From 13ea850c663ed5a2637b0333f71c5c1805ab49da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Mon, 31 Aug 2026 20:57:41 +0200 Subject: [PATCH 4/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Docs/pages/01-create-mocks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Docs/pages/01-create-mocks.md b/Docs/pages/01-create-mocks.md index 5df20ad7..0aea971e 100644 --- a/Docs/pages/01-create-mocks.md +++ b/Docs/pages/01-create-mocks.md @@ -157,8 +157,8 @@ sut.Mock.As().Verify.Restock().Once(); **When the class already implements the interface** -`.Implementing()` is also useful when the mocked class itself implements `T`, because it makes members the -class implements non-virtually reachable: +`.Implementing()` is also useful when the mocked class itself implements `T`, because it makes non-virtual +members that the class implements mockable through the interface slot: ```csharp public interface ICalculator