diff --git a/Docs/pages/05-interaction-tracking.md b/Docs/pages/05-interaction-tracking.md new file mode 100644 index 00000000..bb3c32c8 --- /dev/null +++ b/Docs/pages/05-interaction-tracking.md @@ -0,0 +1,35 @@ +# Interaction Tracking + +Mockolate tracks all interactions with mocks. You can access and manage these interactions: + +```csharp +var sut = Mock.Create(); + +sut.Dispense("Dark", 5); +sut.Dispense("Milk", 3); + +// Access all interactions +Mock mockInstance = ((IMockSubject)sut).Mock; +foreach (var interaction in mockInstance.Interactions.Interactions) +{ + Console.WriteLine($"Interaction: {interaction}"); +} + +// Clear interaction history +sut.SetupMock.ClearAllInteractions(); +``` + +## Mock Monitoring Sessions + +Use `MockMonitor.Run()` to track interactions within a specific scope: + +```csharp +var sut = Mock.Create(); +using (var monitor = sut.MonitorMock(out MockMonitor monitorInstance)) +{ + sut.Dispense("Dark", 5); + + // Verify interactions within this session + monitorInstance.Verify.Invoked.Dispense(It.Is("Dark"), It.Is(5)).Once(); +} +``` diff --git a/README.md b/README.md index 38611181..9fbea7d5 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,42 @@ sut.VerifyMock.Invoked.Dispense(It.Is("Dark"), It.Is(1)).Then( If the order is incorrect or a call is missing, a `MockVerificationException` will be thrown with a descriptive message. +## Interaction Tracking + +Mockolate tracks all interactions with mocks. You can access and manage these interactions: + +```csharp +var sut = Mock.Create(); + +sut.Dispense("Dark", 5); +sut.Dispense("Milk", 3); + +// Access all interactions +Mock mockInstance = ((IMockSubject)sut).Mock; +foreach (var interaction in mockInstance.Interactions.Interactions) +{ + Console.WriteLine($"Interaction: {interaction}"); +} + +// Clear interaction history +sut.SetupMock.ClearAllInteractions(); +``` + +### Mock Monitoring Sessions + +Use `MockMonitor.Run()` to track interactions within a specific scope: + +```csharp +var sut = Mock.Create(); +using (var monitor = sut.MonitorMock(out MockMonitor monitorInstance)) +{ + sut.Dispense("Dark", 5); + + // Verify interactions within this session + monitorInstance.Verify.Invoked.Dispense(It.Is("Dark"), It.Is(5)).Once(); +} +``` + ## Advanced Features ### Working with protected members diff --git a/Tests/Mockolate.ExampleTests/ExampleTests.cs b/Tests/Mockolate.ExampleTests/ExampleTests.cs index 6ef4a871..5bd78232 100644 --- a/Tests/Mockolate.ExampleTests/ExampleTests.cs +++ b/Tests/Mockolate.ExampleTests/ExampleTests.cs @@ -2,6 +2,7 @@ using System.IO.Abstractions; using System.Threading.Tasks; using Mockolate.ExampleTests.TestData; +using Mockolate.Monitor; using Mockolate.Verify; #if NET8_0_OR_GREATER using System.Net; @@ -201,4 +202,58 @@ public async Task WithOut_ShouldSupportOutParameter(bool returnValue) await That(result).IsEqualTo(returnValue); mock.VerifyMock.Invoked.TryDelete(It.Is(id), It.IsOut()).Once(); } + + [Fact] + public async Task InteractionTracking_ShouldTrackAllInteractions() + { + Guid id1 = Guid.NewGuid(); + Guid id2 = Guid.NewGuid(); + IExampleRepository sut = Mock.Create(); + + sut.AddUser("Alice"); + sut.RemoveUser(id1); + sut.AddUser("Bob"); + + // Access all interactions via cast to access the concrete Mock type + Mock mockInstance = ((IMockSubject)sut).Mock; + await That(mockInstance.Interactions.Count).IsEqualTo(3); + await That(mockInstance.Interactions.Interactions).HasCount(3); + + // Clear interaction history + sut.SetupMock.ClearAllInteractions(); + await That(mockInstance.Interactions.Count).IsEqualTo(0); + } + +#if NET8_0_OR_GREATER + [Fact] + public async Task MockMonitoring_ShouldTrackScopedInteractions() + { + Guid id1 = Guid.NewGuid(); + Guid id2 = Guid.NewGuid(); + IExampleRepository sut = Mock.Create(); + sut.SetupMock.Method.AddUser(It.IsAny()).Returns(name => new User(Guid.NewGuid(), name)); + + sut.AddUser("Before"); + + using (IDisposable monitor = sut.MonitorMock(out MockMonitor monitorInstance)) + { + sut.AddUser("Alice"); + sut.AddUser("Bob"); + + // Verify interactions within this session only + monitorInstance.Verify.Invoked.AddUser(It.Is("Alice")).Once(); + monitorInstance.Verify.Invoked.AddUser(It.Is("Bob")).Once(); + // "Before" was called outside the monitoring session + monitorInstance.Verify.Invoked.AddUser(It.Is("Before")).Never(); + } + + sut.AddUser("After"); + + // The main mock still tracks all interactions + sut.VerifyMock.Invoked.AddUser(It.Is("Before")).Once(); + sut.VerifyMock.Invoked.AddUser(It.Is("Alice")).Once(); + sut.VerifyMock.Invoked.AddUser(It.Is("Bob")).Once(); + sut.VerifyMock.Invoked.AddUser(It.Is("After")).Once(); + } +#endif }