docs: describe reaching a mock's other interfaces - #855
Conversation
The "Implementing additional interfaces" section covered `.Implementing<T>()` and `Mock.As<T>()` but left out how they behave in practice. Adds: - the cast accessor `((ILemonadeDispenser)sut).Mock`, which reaches the same surface without the `As<T>()` hop - `Mock.As<T>()` throwing `MockException` for a type the mock does not implement - `Mock.As<TBase>()` reaching a base interface member the mocked interface hides with `new`, which needs no `.Implementing<T>()` and keeps the two slots apart - what `.Implementing<T>()` does with a class that already implements the interface: members it implements non-virtually are reachable only through the interface slot - that `.Implementing<T>()` 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.
There was a problem hiding this comment.
Pull request overview
This PR clarifies how to access and reason about a mock’s “other interface” surfaces in Mockolate, expanding the docs around .Implementing<T>() and Mock.As<T>() to better match real generator/runtime behavior.
Changes:
- Adds examples for accessing an additional interface’s mock surface via a casted interface’s
.Mockaccessor (skipping theAs<T>()hop). - Documents
Mock.As<T>()error behavior whenTisn’t implemented, and illustrates usingAs<TBase>()to reach hidden base-interface members. - Explains
.Implementing<T>()behavior for class mocks that already implement an interface (virtual vs non-virtual members), plus notes about returning a new instance, constructor parameter reuse, and indexer behavior.
Suppressed comments (1)
Docs/pages/01-create-mocks.md:200
- The note “Indexers are keyed by their parameter signature” is ambiguous and (taken literally) overbroad: this project has tests ensuring indexers with the same parameter types but different return/value types do not collide. The important point here is that indexer identity is not scoped by declaring interface, so base/derived indexers that only differ by
new/declaring interface can share storage.
- 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.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
🚀 Benchmark ResultsDetails
Details
Details
Details
Details
Details
|
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
…interfaces (#855) by Valentin Breuß
…interfaces (#855) by Valentin Breuß



The "Implementing additional interfaces" section covered
.Implementing<T>()andMock.As<T>()but left out how they behave in practice. Adds:((ILemonadeDispenser)sut).Mock, which reaches the same surface without theAs<T>()hopMock.As<T>()throwingMockExceptionfor a type the mock does not implementMock.As<TBase>()reaching a base interface member the mocked interface hides withnew, which needs no.Implementing<T>()and keeps the two slots apart.Implementing<T>()does with a class that already implements the interface: members it implements non-virtually are reachable only through the interface slot.Implementing<T>()returns a new instance, that it carries the constructor parameters over, and that indexers share storage across anewEvery sample was compiled and run against the generator.