Skip to content

Commit 212c69c

Browse files
committed
Refactor tests for ActivityExecutionStoreExtensions
- Replace mock setup with `CreateStore` helper for clean and clear test arrangements. - Remove unused imports and clean up test setup for improved readability and maintenance.
1 parent 8ad3018 commit 212c69c

2 files changed

Lines changed: 25 additions & 40 deletions

File tree

src/modules/Elsa.Workflows.Runtime/Stores/MemoryActivityExecutionStore.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using Elsa.Common.Models;
21
using Elsa.Common.Services;
32
using Elsa.Extensions;
43
using Elsa.Workflows.Runtime.Entities;

test/unit/Elsa.Workflows.Runtime.UnitTests/Extensions/ActivityExecutionStoreExtensionsTests.cs

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1+
using Elsa.Common.Models;
2+
using Elsa.Common.Services;
13
using Elsa.Workflows.Runtime.Entities;
2-
using Elsa.Workflows.Runtime.Filters;
3-
using Moq;
4+
using Elsa.Workflows.Runtime.Stores;
45

56
namespace Elsa.Workflows.Runtime.UnitTests.Extensions;
67

78
public class ActivityExecutionStoreExtensionsTests
89
{
9-
private readonly Mock<IActivityExecutionStore> _storeMock = new();
10-
1110
[Fact(DisplayName = "GetExecutionChainAsync returns empty page when record not found")]
1211
public async Task GetExecutionChainAsync_ReturnsEmptyPage_WhenRecordNotFound()
1312
{
1413
// Arrange
15-
_storeMock
16-
.Setup(x => x.FindAsync(It.IsAny<ActivityExecutionRecordFilter>(), It.IsAny<CancellationToken>()))
17-
.ReturnsAsync((ActivityExecutionRecord?)null);
14+
var store = CreateStore();
1815

1916
// Act
20-
var result = await _storeMock.Object.GetExecutionChainAsync("non-existent-id");
17+
var result = await store.GetExecutionChainAsync("non-existent-id");
2118

2219
// Assert
2320
Assert.Empty(result.Items);
@@ -28,20 +25,20 @@ public async Task GetExecutionChainAsync_ReturnsEmptyPage_WhenRecordNotFound()
2825
public async Task GetExecutionChainAsync_ReturnsSingleRecord_WhenNoParent()
2926
{
3027
// Arrange
31-
SetupStore(CreateChain(1));
28+
var store = CreateStore(CreateChain(1));
3229

3330
// Act & Assert
34-
await AssertChainAsync("record-1", expectedIds: ["record-1"]);
31+
await AssertChainAsync(store, "record-1", expectedIds: ["record-1"]);
3532
}
3633

3734
[Fact(DisplayName = "GetExecutionChainAsync traverses chain correctly with multiple levels")]
3835
public async Task GetExecutionChainAsync_TraversesChainCorrectly_WithMultipleLevels()
3936
{
4037
// Arrange
41-
SetupStore(CreateChain(3));
38+
var store = CreateStore(CreateChain(3));
4239

4340
// Act & Assert
44-
await AssertChainAsync("record-3", expectedIds: ["record-1", "record-2", "record-3"]);
41+
await AssertChainAsync(store, "record-3", expectedIds: ["record-1", "record-2", "record-3"]);
4542
}
4643

4744
[Theory(DisplayName = "GetExecutionChainAsync respects workflow boundary based on includeCrossWorkflowChain")]
@@ -53,10 +50,10 @@ public async Task GetExecutionChainAsync_RespectsWorkflowBoundary(bool includeCr
5350
var parentRecord = CreateRecord("parent-record", "parent-workflow", null);
5451
var childRoot = CreateRecord("child-root", "child-workflow", "parent-record", "parent-workflow");
5552
var childLeaf = CreateRecord("child-leaf", "child-workflow", "child-root");
56-
SetupStore(parentRecord, childRoot, childLeaf);
53+
var store = CreateStore(parentRecord, childRoot, childLeaf);
5754

5855
// Act & Assert
59-
await AssertChainAsync("child-leaf", expectedIds, includeCrossWorkflowChain: includeCrossWorkflowChain);
56+
await AssertChainAsync(store, "child-leaf", expectedIds, includeCrossWorkflowChain: includeCrossWorkflowChain);
6057
}
6158

6259
[Theory(DisplayName = "GetExecutionChainAsync applies pagination correctly")]
@@ -67,10 +64,10 @@ public async Task GetExecutionChainAsync_RespectsWorkflowBoundary(bool includeCr
6764
public async Task GetExecutionChainAsync_AppliesPagination(int skip, int? take, int expectedTotal, string[] expectedIds)
6865
{
6966
// Arrange
70-
SetupStore(CreateChain(4));
67+
var store = CreateStore(CreateChain(4));
7168

7269
// Act
73-
var result = await _storeMock.Object.GetExecutionChainAsync("record-4", skip: skip, take: take);
70+
var result = await store.GetExecutionChainAsync("record-4", skip: skip, take: take);
7471
var items = result.Items.ToList();
7572

7673
// Assert
@@ -84,25 +81,33 @@ public async Task GetExecutionChainAsync_HandlesCircularReference_Gracefully()
8481
// Arrange: Create a circular reference (which shouldn't happen in practice, but should be handled)
8582
var record1 = CreateRecord("record-1", "workflow-1", "record-2");
8683
var record2 = CreateRecord("record-2", "workflow-1", "record-1");
87-
SetupStore(record1, record2);
84+
var store = CreateStore(record1, record2);
8885

8986
// Act
90-
var result = await _storeMock.Object.GetExecutionChainAsync("record-1");
87+
var result = await store.GetExecutionChainAsync("record-1");
9188

9289
// Assert: Should have visited both records (once each) and stopped
9390
Assert.Equal(2, result.Items.Count);
9491
}
9592

9693
#region Helpers
9794

98-
private async Task AssertChainAsync(
95+
private static MemoryActivityExecutionStore CreateStore(params ActivityExecutionRecord[] records)
96+
{
97+
var memoryStore = new MemoryStore<ActivityExecutionRecord>();
98+
memoryStore.SaveMany(records, r => r.Id);
99+
return new MemoryActivityExecutionStore(memoryStore);
100+
}
101+
102+
private static async Task AssertChainAsync(
103+
IActivityExecutionStore store,
99104
string startRecordId,
100105
string[] expectedIds,
101106
bool includeCrossWorkflowChain = true,
102107
int skip = 0,
103108
int? take = null)
104109
{
105-
var result = await _storeMock.Object.GetExecutionChainAsync(startRecordId, includeCrossWorkflowChain, skip, take);
110+
var result = await store.GetExecutionChainAsync(startRecordId, includeCrossWorkflowChain, skip, take);
106111
var items = result.Items.ToList();
107112

108113
Assert.Equal(expectedIds.Length, items.Count);
@@ -141,24 +146,5 @@ private static ActivityExecutionRecord CreateRecord(
141146
SchedulingWorkflowInstanceId = schedulingWorkflowInstanceId
142147
};
143148

144-
private void SetupStore(params ActivityExecutionRecord[] records)
145-
{
146-
var recordsDict = records.ToDictionary(r => r.Id);
147-
var recordsByWorkflow = records.GroupBy(r => r.WorkflowInstanceId)
148-
.ToDictionary(g => g.Key, g => g.ToList());
149-
150-
_storeMock
151-
.Setup(x => x.FindAsync(It.IsAny<ActivityExecutionRecordFilter>(), It.IsAny<CancellationToken>()))
152-
.ReturnsAsync((ActivityExecutionRecordFilter filter, CancellationToken _) =>
153-
filter.Id != null && recordsDict.TryGetValue(filter.Id, out var record) ? record : null);
154-
155-
_storeMock
156-
.Setup(x => x.FindManyAsync(It.IsAny<ActivityExecutionRecordFilter>(), It.IsAny<CancellationToken>()))
157-
.ReturnsAsync((ActivityExecutionRecordFilter filter, CancellationToken _) =>
158-
filter.WorkflowInstanceId != null && recordsByWorkflow.TryGetValue(filter.WorkflowInstanceId, out var workflowRecords)
159-
? workflowRecords.AsEnumerable()
160-
: Enumerable.Empty<ActivityExecutionRecord>());
161-
}
162-
163149
#endregion
164150
}

0 commit comments

Comments
 (0)