Skip to content

Commit 8f5956b

Browse files
authored
Replace Moq with NSubstitute (#256)
1 parent aee3db3 commit 8f5956b

9 files changed

+130
-149
lines changed

tests/CacheTower.Tests/CacheStackTests.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Threading.Tasks;
66
using CacheTower.Providers.Memory;
77
using Microsoft.VisualStudio.TestTools.UnitTesting;
8-
using Moq;
8+
using NSubstitute;
99

1010
namespace CacheTower.Tests
1111
{
@@ -83,13 +83,13 @@ public async Task Evict_EvictsAllTheLayers()
8383
[TestMethod]
8484
public async Task Evict_TriggersCacheChangeExtension()
8585
{
86-
var mockExtension = new Mock<ICacheChangeExtension>();
87-
await using var cacheStack = new CacheStack(null, new(new[] { new MemoryCacheLayer() }) { Extensions = new[] { mockExtension.Object } });
86+
var mockExtension = Substitute.For<ICacheChangeExtension>();
87+
await using var cacheStack = new CacheStack(null, new(new[] { new MemoryCacheLayer() }) { Extensions = new[] { mockExtension } });
8888
var cacheEntry = await cacheStack.SetAsync("Evict_TriggerCacheChangeExtension", 42, TimeSpan.FromDays(1));
8989

9090
await cacheStack.EvictAsync("Evict_TriggerCacheChangeExtension");
9191

92-
mockExtension.Verify(e => e.OnCacheEvictionAsync("Evict_TriggerCacheChangeExtension"), Times.Once);
92+
await mockExtension.Received(1).OnCacheEvictionAsync("Evict_TriggerCacheChangeExtension");
9393
}
9494
[TestMethod, ExpectedException(typeof(ObjectDisposedException))]
9595
public async Task Evict_ThrowsOnUseAfterDisposal()
@@ -122,12 +122,12 @@ public async Task Flush_FlushesAllTheLayers()
122122
[TestMethod]
123123
public async Task Flush_TriggersCacheChangeExtension()
124124
{
125-
var mockExtension = new Mock<ICacheChangeExtension>();
126-
await using var cacheStack = new CacheStack(null, new(new[] { new MemoryCacheLayer() }) { Extensions = new[] { mockExtension.Object } });
125+
var mockExtension = Substitute.For<ICacheChangeExtension>();
126+
await using var cacheStack = new CacheStack(null, new(new[] { new MemoryCacheLayer() }) { Extensions = new[] { mockExtension } });
127127

128128
await cacheStack.FlushAsync();
129129

130-
mockExtension.Verify(e => e.OnCacheFlushAsync(), Times.Once);
130+
await mockExtension.Received(1).OnCacheFlushAsync();
131131
}
132132
[TestMethod, ExpectedException(typeof(ObjectDisposedException))]
133133
public async Task Flush_ThrowsOnUseAfterDisposal()
@@ -201,11 +201,11 @@ public async Task Set_SetsAllTheLayers()
201201
[TestMethod]
202202
public async Task Set_TriggersCacheChangeExtension()
203203
{
204-
var mockExtension = new Mock<ICacheChangeExtension>();
205-
await using var cacheStack = new CacheStack(null, new(new[] { new MemoryCacheLayer() }) { Extensions = new[] { mockExtension.Object } });
204+
var mockExtension = Substitute.For<ICacheChangeExtension>();
205+
await using var cacheStack = new CacheStack(null, new(new[] { new MemoryCacheLayer() }) { Extensions = new[] { mockExtension } });
206206
var cacheEntry = await cacheStack.SetAsync("Set_TriggersCacheChangeExtension", 42, TimeSpan.FromDays(1));
207207

208-
mockExtension.Verify(e => e.OnCacheUpdateAsync("Set_TriggersCacheChangeExtension", cacheEntry.Expiry, CacheUpdateType.AddOrUpdateEntry), Times.Once);
208+
await mockExtension.Received(1).OnCacheUpdateAsync("Set_TriggersCacheChangeExtension", cacheEntry.Expiry, CacheUpdateType.AddOrUpdateEntry);
209209
}
210210

211211
[TestMethod, ExpectedException(typeof(ArgumentNullException))]

tests/CacheTower.Tests/CacheTower.Tests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
<ItemGroup>
1010
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
1111
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
12-
<PackageReference Include="Moq" Version="4.18.1" />
1312
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
1413
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
1514
<PackageReference Include="coverlet.collector" Version="6.0.0">
1615
<PrivateAssets>all</PrivateAssets>
1716
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1817
</PackageReference>
1918
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All" Version="1.0.3" />
19+
<PackageReference Include="NSubstitute" Version="5.0.0" />
2020
</ItemGroup>
2121

2222
<ItemGroup>

tests/CacheTower.Tests/Extensions/AutoCleanupExtensionTests.cs

+8-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
using CacheTower.Extensions;
88
using CacheTower.Providers.Memory;
99
using Microsoft.VisualStudio.TestTools.UnitTesting;
10-
using Moq;
10+
using NSubstitute;
11+
using NSubstitute.ReceivedExtensions;
1112

1213
namespace CacheTower.Tests.Extensions
1314
{
@@ -34,20 +35,20 @@ public async Task ThrowForRegisteringTwoCacheStacks()
3435
public async Task RunsBackgroundCleanup()
3536
{
3637
await using var extension = new AutoCleanupExtension(TimeSpan.FromMilliseconds(500));
37-
var cacheStackMock = new Mock<ICacheStack>();
38-
extension.Register(cacheStackMock.Object);
38+
var cacheStackMock = Substitute.For<ICacheStack>();
39+
extension.Register(cacheStackMock);
3940
await Task.Delay(TimeSpan.FromSeconds(2));
40-
cacheStackMock.Verify(c => c.CleanupAsync(), Times.AtLeast(2));
41+
await cacheStackMock.Received(Quantity.Within(2, int.MaxValue)).CleanupAsync();
4142
}
4243

4344
[TestMethod]
4445
public async Task BackgroundCleanupObeysCancel()
4546
{
4647
await using var extension = new AutoCleanupExtension(TimeSpan.FromMilliseconds(500), new CancellationToken(true));
47-
var cacheStackMock = new Mock<ICacheStack>();
48-
extension.Register(cacheStackMock.Object);
48+
var cacheStackMock = Substitute.For<ICacheStack>();
49+
extension.Register(cacheStackMock);
4950
await Task.Delay(TimeSpan.FromSeconds(2));
50-
cacheStackMock.Verify(c => c.CleanupAsync(), Times.Never);
51+
await cacheStackMock.DidNotReceive().CleanupAsync();
5152
}
5253
}
5354
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
52
using System.Threading.Tasks;
63
using CacheTower.Extensions;
74
using Microsoft.VisualStudio.TestTools.UnitTesting;
8-
using Moq;
5+
using NSubstitute;
96

107
namespace CacheTower.Tests.Extensions
118
{
@@ -27,76 +24,67 @@ public async Task AcceptsEmptyExtensions()
2724
[TestMethod]
2825
public async Task DistributedLockExtension()
2926
{
30-
var cacheStackMock = new Mock<ICacheStack>();
31-
var distributedLockMock = new Mock<IDistributedLockExtension>();
32-
await using var container = new ExtensionContainer(new[] { distributedLockMock.Object });
27+
var cacheStackMock = Substitute.For<ICacheStack>();
28+
var distributedLockMock = Substitute.For<IDistributedLockExtension>();
29+
await using var container = new ExtensionContainer(new[] { distributedLockMock });
3330

34-
container.Register(cacheStackMock.Object);
31+
container.Register(cacheStackMock);
3532

3633
var distributedLock = await container.AwaitAccessAsync("DistributedLockCacheKey");
3734

38-
distributedLockMock.Verify(e => e.Register(cacheStackMock.Object), Times.Once);
39-
distributedLockMock.Verify(e => e.AwaitAccessAsync("DistributedLockCacheKey"), Times.Once);
35+
distributedLockMock.Received(1).Register(cacheStackMock);
36+
await distributedLockMock.Received(1).AwaitAccessAsync("DistributedLockCacheKey");
4037
}
4138

4239
[TestMethod]
4340
public async Task CacheChangeExtension_Update()
4441
{
45-
var cacheStackMock = new Mock<ICacheStack>();
46-
var valueRefreshMock = new Mock<ICacheChangeExtension>();
47-
await using var container = new ExtensionContainer(new[] { valueRefreshMock.Object });
42+
var cacheStackMock = Substitute.For<ICacheStack>();
43+
var valueRefreshMock = Substitute.For<ICacheChangeExtension>();
44+
await using var container = new ExtensionContainer(new[] { valueRefreshMock });
4845

49-
container.Register(cacheStackMock.Object);
46+
container.Register(cacheStackMock);
5047

5148
var expiry = DateTime.UtcNow.AddDays(1);
5249

5350
await container.OnCacheUpdateAsync("CacheChangeKey", expiry, CacheUpdateType.AddEntry);
5451

55-
valueRefreshMock.Verify(e => e.Register(cacheStackMock.Object), Times.Once);
56-
valueRefreshMock.Verify(e =>
57-
e.OnCacheUpdateAsync("CacheChangeKey", expiry, CacheUpdateType.AddEntry),
58-
Times.Once
59-
);
52+
valueRefreshMock.Received(1).Register(cacheStackMock);
53+
await valueRefreshMock.Received(1).OnCacheUpdateAsync("CacheChangeKey", expiry, CacheUpdateType.AddEntry);
6054
}
6155

6256
[TestMethod]
6357
public async Task CacheChangeExtension_Eviction()
6458
{
65-
var cacheStackMock = new Mock<ICacheStack>();
66-
var valueRefreshMock = new Mock<ICacheChangeExtension>();
67-
await using var container = new ExtensionContainer(new[] { valueRefreshMock.Object });
59+
var cacheStackMock = Substitute.For<ICacheStack>();
60+
var valueRefreshMock = Substitute.For<ICacheChangeExtension>();
61+
await using var container = new ExtensionContainer(new[] { valueRefreshMock });
6862

69-
container.Register(cacheStackMock.Object);
63+
container.Register(cacheStackMock);
7064

7165
var expiry = DateTime.UtcNow.AddDays(1);
7266

7367
await container.OnCacheEvictionAsync("CacheChangeKey");
7468

75-
valueRefreshMock.Verify(e => e.Register(cacheStackMock.Object), Times.Once);
76-
valueRefreshMock.Verify(e =>
77-
e.OnCacheEvictionAsync("CacheChangeKey"),
78-
Times.Once
79-
);
69+
valueRefreshMock.Received(1).Register(cacheStackMock);
70+
await valueRefreshMock.Received(1).OnCacheEvictionAsync("CacheChangeKey");
8071
}
8172

8273
[TestMethod]
8374
public async Task CacheChangeExtension_Flush()
8475
{
85-
var cacheStackMock = new Mock<ICacheStack>();
86-
var valueRefreshMock = new Mock<ICacheChangeExtension>();
87-
await using var container = new ExtensionContainer(new[] { valueRefreshMock.Object });
76+
var cacheStackMock = Substitute.For<ICacheStack>();
77+
var valueRefreshMock = Substitute.For<ICacheChangeExtension>();
78+
await using var container = new ExtensionContainer(new[] { valueRefreshMock });
8879

89-
container.Register(cacheStackMock.Object);
80+
container.Register(cacheStackMock);
9081

9182
var expiry = DateTime.UtcNow.AddDays(1);
9283

9384
await container.OnCacheFlushAsync();
9485

95-
valueRefreshMock.Verify(e => e.Register(cacheStackMock.Object), Times.Once);
96-
valueRefreshMock.Verify(e =>
97-
e.OnCacheFlushAsync(),
98-
Times.Once
99-
);
86+
valueRefreshMock.Received(1).Register(cacheStackMock);
87+
await valueRefreshMock.Received(1).OnCacheFlushAsync();
10088
}
10189
}
10290
}

tests/CacheTower.Tests/Extensions/Redis/RedisLockExtensionTests.cs

+12-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using CacheTower.Extensions.Redis;
44
using CacheTower.Tests.Utils;
55
using Microsoft.VisualStudio.TestTools.UnitTesting;
6-
using Moq;
6+
using NSubstitute;
77
using StackExchange.Redis;
88

99
namespace CacheTower.Tests.Extensions.Redis;
@@ -33,7 +33,7 @@ public void ThrowForNullChannel()
3333
public void ThrowForRegisteringTwoCacheStacks()
3434
{
3535
var extension = new RedisLockExtension(RedisHelper.GetConnection());
36-
var cacheStack = new Mock<ICacheStack>().Object;
36+
var cacheStack = Substitute.For<ICacheStack>();
3737
extension.Register(cacheStack);
3838
extension.Register(cacheStack);
3939
}
@@ -68,9 +68,9 @@ public async Task RefreshValueNotifiesChannelSubscribers()
6868

6969
var connection = RedisHelper.GetConnection();
7070

71-
var cacheStackMock = new Mock<ICacheStack>();
71+
var cacheStackMock = Substitute.For<ICacheStack>();
7272
var extension = new RedisLockExtension(connection, RedisLockOptions.Default);
73-
extension.Register(cacheStackMock.Object);
73+
extension.Register(cacheStackMock);
7474

7575
var completionSource = new TaskCompletionSource<bool>();
7676

@@ -112,9 +112,9 @@ public async Task ObservedLockSingle()
112112

113113
var connection = RedisHelper.GetConnection();
114114

115-
var cacheStackMock = new Mock<ICacheStack>();
115+
var cacheStackMock = Substitute.For<ICacheStack>();
116116
var extension = new RedisLockExtension(connection, RedisLockOptions.Default);
117-
extension.Register(cacheStackMock.Object);
117+
extension.Register(cacheStackMock);
118118

119119
//Establish lock
120120
await connection.GetDatabase().StringSetAsync("Lock:TestKey", RedisValue.EmptyString);
@@ -143,9 +143,9 @@ public async Task ObservedLockMultiple()
143143

144144
var connection = RedisHelper.GetConnection();
145145

146-
var cacheStackMock = new Mock<ICacheStack>();
146+
var cacheStackMock = Substitute.For<ICacheStack>();
147147
var extension = new RedisLockExtension(connection, RedisLockOptions.Default);
148-
extension.Register(cacheStackMock.Object);
148+
extension.Register(cacheStackMock);
149149

150150
//Establish lock
151151
await connection.GetDatabase().StringSetAsync("Lock:TestKey", RedisValue.EmptyString);
@@ -178,9 +178,9 @@ public async Task FailsafeOnSubscriberFailure()
178178

179179
var connection = RedisHelper.GetConnection();
180180

181-
var cacheStackMock = new Mock<ICacheStack>();
181+
var cacheStackMock = Substitute.For<ICacheStack>();
182182
var extension = new RedisLockExtension(connection, RedisLockOptions.Default with { LockTimeout = TimeSpan.FromSeconds(1) });
183-
extension.Register(cacheStackMock.Object);
183+
extension.Register(cacheStackMock);
184184

185185
//Establish lock
186186
await connection.GetDatabase().StringSetAsync("Lock:TestKey", RedisValue.EmptyString);
@@ -212,9 +212,9 @@ public async Task BusyLockCheckWorksWhenSubscriberFails()
212212

213213
var connection = RedisHelper.GetConnection();
214214

215-
var cacheStackMock = new Mock<ICacheStack>();
215+
var cacheStackMock = Substitute.For<ICacheStack>();
216216
var extension = new RedisLockExtension(connection, RedisLockOptions.Default with { LockCheckStrategy = LockCheckStrategy.WithSpinLock(TimeSpan.FromMilliseconds(50)) });
217-
extension.Register(cacheStackMock.Object);
217+
extension.Register(cacheStackMock);
218218

219219
//Establish lock
220220
await connection.GetDatabase().StringSetAsync("Lock:TestKey", RedisValue.EmptyString);

0 commit comments

Comments
 (0)