Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions Docs/pages/05-interaction-tracking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Interaction Tracking

Mockolate tracks all interactions with mocks. You can access and manage these interactions:

```csharp
var sut = Mock.Create<IChocolateDispenser>();

sut.Dispense("Dark", 5);
sut.Dispense("Milk", 3);

// Access all interactions
Mock<IChocolateDispenser> mockInstance = ((IMockSubject<IChocolateDispenser>)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<IChocolateDispenser>();
using (var monitor = sut.MonitorMock(out MockMonitor<IChocolateDispenser> monitorInstance))
{
sut.Dispense("Dark", 5);

// Verify interactions within this session
monitorInstance.Verify.Invoked.Dispense(It.Is("Dark"), It.Is(5)).Once();
}
```
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<IChocolateDispenser>();

sut.Dispense("Dark", 5);
sut.Dispense("Milk", 3);

// Access all interactions
Mock<IChocolateDispenser> mockInstance = ((IMockSubject<IChocolateDispenser>)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<IChocolateDispenser>();
using (var monitor = sut.MonitorMock(out MockMonitor<IChocolateDispenser> 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
Expand Down
55 changes: 55 additions & 0 deletions Tests/Mockolate.ExampleTests/ExampleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<User?>()).Once();
}

[Fact]
public async Task InteractionTracking_ShouldTrackAllInteractions()
{
Guid id1 = Guid.NewGuid();
Guid id2 = Guid.NewGuid();
IExampleRepository sut = Mock.Create<IExampleRepository>();

sut.AddUser("Alice");
sut.RemoveUser(id1);
sut.AddUser("Bob");

// Access all interactions via cast to access the concrete Mock type
Mock<IExampleRepository> mockInstance = ((IMockSubject<IExampleRepository>)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<IExampleRepository>();
sut.SetupMock.Method.AddUser(It.IsAny<string>()).Returns(name => new User(Guid.NewGuid(), name));

sut.AddUser("Before");

using (IDisposable monitor = sut.MonitorMock(out MockMonitor<IExampleRepository> 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
}