From 724c2a60ba2acc1d71f36653b1baade7b65af2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sat, 31 Jan 2026 13:12:54 +0100 Subject: [PATCH 1/3] docs: document `MockMonitor` and `ClearAllInteractions` --- .../03-monitor-interactions.md | 34 ++++++++++++++++ ...> 04-check-for-unexpected-interactions.md} | 4 +- Mockolate.slnx | 3 +- README.md | 39 ++++++++++++++++++- .../Monitor/MockMonitorTests.cs | 21 ++++------ 5 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 Docs/pages/advanced-features/03-monitor-interactions.md rename Docs/pages/advanced-features/{03-check-for-unexpected-interactions.md => 04-check-for-unexpected-interactions.md} (92%) diff --git a/Docs/pages/advanced-features/03-monitor-interactions.md b/Docs/pages/advanced-features/03-monitor-interactions.md new file mode 100644 index 00000000..1ce0d733 --- /dev/null +++ b/Docs/pages/advanced-features/03-monitor-interactions.md @@ -0,0 +1,34 @@ +# Monitor interactions + +Mockolate tracks all interactions with mocks on the mock object. To only track interactions within a given scope, you +can use a `MockMonitor`: + +```csharp +var sut = Mock.Create(); + +sut.Dispense("Dark", 1); // Not monitored +using (var monitor = sut.MonitorMock(out var monitor)) +{ + sut.Dispense("Dark", 2); // Monitored +} +sut.Dispense("Dark", 3); // Not monitored + +// Verifications on the monitor only count interactions during the lifetime scope of the `IDisposable` +monitor.Verify.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); +``` + +## Clear all interactions + +For simpler scenarios you can directly clear all recorded interactions on a mock using `ClearAllInteractions` on the +setup: + +```csharp +var sut = Mock.Create(); + +sut.Dispense("Dark", 1); +// Clears all previously recorded interactions +sut.SetupMock.ClearAllInteractions(); +sut.Dispense("Dark", 2); + +monitor.Verify.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); +``` diff --git a/Docs/pages/advanced-features/03-check-for-unexpected-interactions.md b/Docs/pages/advanced-features/04-check-for-unexpected-interactions.md similarity index 92% rename from Docs/pages/advanced-features/03-check-for-unexpected-interactions.md rename to Docs/pages/advanced-features/04-check-for-unexpected-interactions.md index c3474f37..0ecae54f 100644 --- a/Docs/pages/advanced-features/03-check-for-unexpected-interactions.md +++ b/Docs/pages/advanced-features/04-check-for-unexpected-interactions.md @@ -1,6 +1,6 @@ # Check for unexpected interactions -## ThatAllInteractionsAreVerified +## That all interactions are verified You can check if all interactions with the mock have been verified using `ThatAllInteractionsAreVerified`: @@ -12,7 +12,7 @@ bool allVerified = sut.VerifyMock.ThatAllInteractionsAreVerified(); This is useful for ensuring that your test covers all interactions and that no unexpected calls were made. If any interaction was not verified, this method returns `false`. -## ThatAllSetupsAreUsed +## That all setups are used You can check if all registered setups on the mock have been used using `ThatAllSetupsAreUsed`: diff --git a/Mockolate.slnx b/Mockolate.slnx index 1b917480..4cbf5818 100644 --- a/Mockolate.slnx +++ b/Mockolate.slnx @@ -51,7 +51,8 @@ - + + diff --git a/README.md b/README.md index 922c859d..42d523fb 100644 --- a/README.md +++ b/README.md @@ -736,9 +736,44 @@ sut.SetupMock.Property.TotalDispensed.OnGet .Do((count, value) => Console.WriteLine($"Read #{count}, value: {value}")); ``` +### Monitor interactions + +Mockolate tracks all interactions with mocks on the mock object. To only track interactions within a given scope, you +can use a `MockMonitor`: + +```csharp +var sut = Mock.Create(); + +sut.Dispense("Dark", 1); // Not monitored +using (var monitor = sut.MonitorMock(out var monitor)) +{ + sut.Dispense("Dark", 2); // Monitored +} +sut.Dispense("Dark", 3); // Not monitored + +// Verifications on the monitor only count interactions during the lifetime scope of the `IDisposable` +monitor.Verify.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); +``` + +#### Clear all interactions + +For simpler scenarios you can directly clear all recorded interactions on a mock using `ClearAllInteractions` on the +setup: + +```csharp +var sut = Mock.Create(); + +sut.Dispense("Dark", 1); +// Clears all previously recorded interactions +sut.SetupMock.ClearAllInteractions(); +sut.Dispense("Dark", 2); + +monitor.Verify.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); +``` + ### Check for unexpected interactions -#### ThatAllInteractionsAreVerified +#### That all interactions are verified You can check if all interactions with the mock have been verified using `ThatAllInteractionsAreVerified`: @@ -750,7 +785,7 @@ bool allVerified = sut.VerifyMock.ThatAllInteractionsAreVerified(); This is useful for ensuring that your test covers all interactions and that no unexpected calls were made. If any interaction was not verified, this method returns `false`. -#### ThatAllSetupsAreUsed +#### That all setups are used You can check if all registered setups on the mock have been used using `ThatAllSetupsAreUsed`: diff --git a/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs b/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs index 9dcd78c0..110fdb26 100644 --- a/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs +++ b/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs @@ -9,8 +9,7 @@ public sealed class MockMonitorTests public async Task ClearAllInteractions_WhenMonitorIsRunning_ShouldClearInternalCollection() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); sut.IsValid(1); using IDisposable disposable = monitor.Run(); @@ -24,8 +23,7 @@ public async Task ClearAllInteractions_WhenMonitorIsRunning_ShouldClearInternalC public async Task DisposeTwice_ShouldNotIncludeMoreInvocations() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); sut.IsValid(1); sut.IsValid(2); @@ -53,8 +51,7 @@ public async Task DisposeTwice_ShouldNotIncludeMoreInvocations() public async Task MultipleRun_ShouldMonitorInvocationsDuringTheRun() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); sut.IsValid(1); sut.IsValid(2); @@ -91,8 +88,7 @@ public async Task MultipleRun_ShouldMonitorInvocationsDuringTheRun() public async Task NestedRun_ShouldThrowInvalidOperationException() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); void Act() { @@ -113,8 +109,7 @@ await That(Act).Throws() public async Task Run_ShouldIncludeAllInvocations() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); using (monitor.Run()) { @@ -134,8 +129,7 @@ public async Task Run_ShouldIncludeAllInvocations() public async Task Run_ShouldMonitorInvocationsDuringTheRun() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); sut.IsValid(1); sut.IsValid(2); @@ -163,8 +157,7 @@ public async Task Run_ShouldMonitorInvocationsDuringTheRun() public async Task Verify_WhileRunning_ShouldBeUpToDate() { IMyService sut = Mock.Create(); - Mock mock = ((IMockSubject)sut).Mock; - MockMonitor monitor = new(mock); + sut.MonitorMock(out MockMonitor monitor); using (monitor.Run()) { From a3c0601dbe0fd92bb315c027ba761c6658f396e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sat, 31 Jan 2026 13:18:11 +0100 Subject: [PATCH 2/3] Fix review issues --- Docs/pages/advanced-features/03-monitor-interactions.md | 5 +++-- README.md | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Docs/pages/advanced-features/03-monitor-interactions.md b/Docs/pages/advanced-features/03-monitor-interactions.md index 1ce0d733..8386e9c0 100644 --- a/Docs/pages/advanced-features/03-monitor-interactions.md +++ b/Docs/pages/advanced-features/03-monitor-interactions.md @@ -7,7 +7,8 @@ can use a `MockMonitor`: var sut = Mock.Create(); sut.Dispense("Dark", 1); // Not monitored -using (var monitor = sut.MonitorMock(out var monitor)) +var monitorScope = sut.MonitorMock(out var monitor); +using (monitorScope) { sut.Dispense("Dark", 2); // Monitored } @@ -30,5 +31,5 @@ sut.Dispense("Dark", 1); sut.SetupMock.ClearAllInteractions(); sut.Dispense("Dark", 2); -monitor.Verify.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); +sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); ``` diff --git a/README.md b/README.md index 42d523fb..3a0ddf3c 100644 --- a/README.md +++ b/README.md @@ -745,7 +745,8 @@ can use a `MockMonitor`: var sut = Mock.Create(); sut.Dispense("Dark", 1); // Not monitored -using (var monitor = sut.MonitorMock(out var monitor)) +var monitorScope = sut.MonitorMock(out var monitor); +using (monitorScope) { sut.Dispense("Dark", 2); // Monitored } @@ -768,7 +769,7 @@ sut.Dispense("Dark", 1); sut.SetupMock.ClearAllInteractions(); sut.Dispense("Dark", 2); -monitor.Verify.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); +sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.IsAny()).Once(); ``` ### Check for unexpected interactions From 0b7aa7ac68c10f9aad7fe9e751192e671c22a343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sat, 31 Jan 2026 13:24:00 +0100 Subject: [PATCH 3/3] Fix failing tests --- .../Monitor/MockMonitorTests.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs b/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs index 110fdb26..9dcd78c0 100644 --- a/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs +++ b/Tests/Mockolate.Tests/Monitor/MockMonitorTests.cs @@ -9,7 +9,8 @@ public sealed class MockMonitorTests public async Task ClearAllInteractions_WhenMonitorIsRunning_ShouldClearInternalCollection() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); sut.IsValid(1); using IDisposable disposable = monitor.Run(); @@ -23,7 +24,8 @@ public async Task ClearAllInteractions_WhenMonitorIsRunning_ShouldClearInternalC public async Task DisposeTwice_ShouldNotIncludeMoreInvocations() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); sut.IsValid(1); sut.IsValid(2); @@ -51,7 +53,8 @@ public async Task DisposeTwice_ShouldNotIncludeMoreInvocations() public async Task MultipleRun_ShouldMonitorInvocationsDuringTheRun() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); sut.IsValid(1); sut.IsValid(2); @@ -88,7 +91,8 @@ public async Task MultipleRun_ShouldMonitorInvocationsDuringTheRun() public async Task NestedRun_ShouldThrowInvalidOperationException() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); void Act() { @@ -109,7 +113,8 @@ await That(Act).Throws() public async Task Run_ShouldIncludeAllInvocations() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); using (monitor.Run()) { @@ -129,7 +134,8 @@ public async Task Run_ShouldIncludeAllInvocations() public async Task Run_ShouldMonitorInvocationsDuringTheRun() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); sut.IsValid(1); sut.IsValid(2); @@ -157,7 +163,8 @@ public async Task Run_ShouldMonitorInvocationsDuringTheRun() public async Task Verify_WhileRunning_ShouldBeUpToDate() { IMyService sut = Mock.Create(); - sut.MonitorMock(out MockMonitor monitor); + Mock mock = ((IMockSubject)sut).Mock; + MockMonitor monitor = new(mock); using (monitor.Run()) {