From b91514e437e838fd5cf72caae79480b18c31ea6d Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 9 Aug 2023 12:51:48 +0100 Subject: [PATCH] Remove Moq Remove Moq and replace with NSubstitute. Resolves #1470. --- Directory.Packages.props | 2 +- eng/Test.targets | 2 +- .../CircuitBreakerResilienceStrategyTests.cs | 39 ++++++----- .../AdvancedCircuitBehaviorTests.cs | 23 ++++--- .../Controller/CircuitStateControllerTests.cs | 66 +++++++++++-------- .../CompositeStrategyBuilderContextTests.cs | 4 +- .../CompositeStrategyBuilderTests.cs | 6 +- .../Retry/RetryResilienceStrategyTests.cs | 10 +-- .../ResilienceStrategyTelemetryTests.cs | 45 ++++++------- .../Telemetry/TelemetryUtilTests.cs | 4 +- .../Timeout/TimeoutResilienceStrategyTests.cs | 27 ++++---- .../Utils/CancellationTokenSourcePoolTests.cs | 7 +- .../Utils/DisposeHelperTests.cs | 16 +++-- .../Utils/OptionsReloadHelperTests.cs | 14 ++-- .../OnRateLimiterRejectedArgumentsTests.cs | 4 +- ...CompositeStrategyBuilderExtensionsTests.cs | 10 +-- .../RateLimiterResilienceStrategyTests.cs | 56 +++++++++------- .../ResilienceRateLimiterTests.cs | 34 ++++++---- test/Polly.Specs/Polly.Specs.csproj | 2 +- .../Registry/PolicyRegistrySpecs.cs | 6 +- .../Registry/ReadOnlyPolicyRegistrySpecs.cs | 6 +- test/Polly.TestUtils/Polly.TestUtils.csproj | 2 +- test/Polly.TestUtils/TestUtilities.cs | 9 ++- 23 files changed, 207 insertions(+), 187 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 3a5e431dfd0..ce5b24e4b09 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,7 +22,7 @@ - + diff --git a/eng/Test.targets b/eng/Test.targets index 2c270eac370..a8baacb3403 100644 --- a/eng/Test.targets +++ b/eng/Test.targets @@ -15,7 +15,7 @@ - + diff --git a/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs index 0d2e75accb7..1ccf2703c99 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Time.Testing; -using Moq; +using NSubstitute; using Polly.CircuitBreaker; using Polly.Telemetry; using Polly.Utils; @@ -9,7 +9,7 @@ namespace Polly.Core.Tests.CircuitBreaker; public class CircuitBreakerResilienceStrategyTests : IDisposable { private readonly FakeTimeProvider _timeProvider; - private readonly Mock _behavior; + private readonly CircuitBehavior _behavior; private readonly ResilienceStrategyTelemetry _telemetry; private readonly CircuitBreakerStrategyOptions _options; private readonly CircuitStateController _controller; @@ -17,15 +17,15 @@ public class CircuitBreakerResilienceStrategyTests : IDisposable public CircuitBreakerResilienceStrategyTests() { _timeProvider = new FakeTimeProvider(); - _behavior = new Mock(MockBehavior.Strict); - _telemetry = TestUtilities.CreateResilienceTelemetry(Mock.Of()); + _behavior = Substitute.For(); + _telemetry = TestUtilities.CreateResilienceTelemetry(Substitute.For()); _options = new CircuitBreakerStrategyOptions(); _controller = new CircuitStateController( CircuitBreakerConstants.DefaultBreakDuration, null, null, null, - _behavior.Object, + _behavior, _timeProvider, _telemetry); } @@ -58,16 +58,15 @@ public async Task Ctor_ManualControl_EnsureAttached() await _options.ManualControl.IsolateAsync(CancellationToken.None); strategy.Invoking(s => s.Execute(_ => 0)).Should().Throw(); - _behavior.Setup(v => v.OnCircuitClosed()); await _options.ManualControl.CloseAsync(CancellationToken.None); - _behavior.Setup(v => v.OnActionSuccess(CircuitState.Closed)); strategy.Invoking(s => s.Execute(_ => 0)).Should().NotThrow(); _options.ManualControl.Dispose(); strategy.Invoking(s => s.Execute(_ => 0)).Should().Throw(); - _behavior.VerifyAll(); + _behavior.Received().OnCircuitClosed(); + _behavior.Received().OnActionSuccess(CircuitState.Closed); } [Fact] @@ -77,10 +76,12 @@ public void Execute_HandledResult_OnFailureCalled() var strategy = Create(); var shouldBreak = false; - _behavior.Setup(v => v.OnActionFailure(CircuitState.Closed, out shouldBreak)); + _behavior.When(v => v.OnActionFailure(CircuitState.Closed, out Arg.Any())) + .Do(x => x[1] = shouldBreak); + strategy.Execute(_ => -1).Should().Be(-1); - _behavior.VerifyAll(); + _behavior.Received().OnActionFailure(CircuitState.Closed, out Arg.Any()); } [Fact] @@ -89,10 +90,9 @@ public void Execute_UnhandledResult_OnActionSuccess() _options.ShouldHandle = args => new ValueTask(args.Result is -1); var strategy = Create(); - _behavior.Setup(v => v.OnActionSuccess(CircuitState.Closed)); strategy.Execute(_ => 0).Should().Be(0); - _behavior.VerifyAll(); + _behavior.Received(1).OnActionSuccess(CircuitState.Closed); } [Fact] @@ -102,11 +102,12 @@ public void Execute_HandledException_OnFailureCalled() var strategy = Create(); var shouldBreak = false; - _behavior.Setup(v => v.OnActionFailure(CircuitState.Closed, out shouldBreak)); + _behavior.When(v => v.OnActionFailure(CircuitState.Closed, out Arg.Any())) + .Do(x => x[1] = shouldBreak); strategy.Invoking(s => s.Execute(_ => throw new InvalidOperationException())).Should().Throw(); - _behavior.VerifyAll(); + _behavior.Received().OnActionFailure(CircuitState.Closed, out Arg.Any()); } [Fact] @@ -117,7 +118,9 @@ public void Execute_UnhandledException_NoCalls() strategy.Invoking(s => s.Execute(_ => throw new ArgumentException())).Should().Throw(); - _behavior.VerifyNoOtherCalls(); + _behavior.DidNotReceiveWithAnyArgs().OnActionFailure(default, out Arg.Any()); + _behavior.DidNotReceiveWithAnyArgs().OnActionSuccess(default); + _behavior.DidNotReceiveWithAnyArgs().OnCircuitClosed(); } public void Dispose() => _controller.Dispose(); @@ -126,10 +129,12 @@ public void Execute_UnhandledException_NoCalls() public void Execute_Ok() { _options.ShouldHandle = _ => PredicateResult.False; - _behavior.Setup(v => v.OnActionSuccess(CircuitState.Closed)); Create().Invoking(s => s.Execute(_ => 0)).Should().NotThrow(); + + _behavior.Received(1).OnActionSuccess(CircuitState.Closed); } - private ReactiveResilienceStrategyBridge Create() => new(new CircuitBreakerResilienceStrategy(_options.ShouldHandle!, _controller, _options.StateProvider, _options.ManualControl)); + private ReactiveResilienceStrategyBridge Create() + => new(new CircuitBreakerResilienceStrategy(_options.ShouldHandle!, _controller, _options.StateProvider, _options.ManualControl)); } diff --git a/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs b/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs index ff768ca79de..def5bd3c73e 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs @@ -1,4 +1,4 @@ -using Moq; +using NSubstitute; using Polly.CircuitBreaker; using Polly.CircuitBreaker.Health; @@ -6,7 +6,7 @@ namespace Polly.Core.Tests.CircuitBreaker.Controller; public class AdvancedCircuitBehaviorTests { - private Mock _metrics = new(MockBehavior.Strict, TimeProvider.System); + private HealthMetrics _metrics = Substitute.For(TimeProvider.System); [InlineData(10, 10, 0.0, 0.1, false)] [InlineData(10, 10, 0.1, 0.1, true)] @@ -21,15 +21,14 @@ public void OnActionFailure_WhenClosed_EnsureCorrectBehavior( double failureThreshold, bool expectedShouldBreak) { - _metrics.Setup(m => m.IncrementFailure()); - _metrics.Setup(m => m.GetHealthInfo()).Returns(new HealthInfo(throughput, failureRate)); + _metrics.GetHealthInfo().Returns(new HealthInfo(throughput, failureRate)); - var behavior = new AdvancedCircuitBehavior(failureThreshold, minimumThruput, _metrics.Object); + var behavior = new AdvancedCircuitBehavior(failureThreshold, minimumThruput, _metrics); behavior.OnActionFailure(CircuitState.Closed, out var shouldBreak); shouldBreak.Should().Be(expectedShouldBreak); - _metrics.VerifyAll(); + _metrics.Received(1).IncrementFailure(); } [InlineData(CircuitState.Closed, true)] @@ -39,7 +38,7 @@ public void OnActionFailure_WhenClosed_EnsureCorrectBehavior( [Theory] public void OnActionFailure_State_EnsureCorrectCalls(CircuitState state, bool shouldIncrementFailure) { - _metrics = new(MockBehavior.Loose, TimeProvider.System); + _metrics = Substitute.For(TimeProvider.System); var sut = Create(); @@ -48,27 +47,27 @@ public void OnActionFailure_State_EnsureCorrectCalls(CircuitState state, bool sh shouldBreak.Should().BeFalse(); if (shouldIncrementFailure) { - _metrics.Verify(v => v.IncrementFailure(), Times.Once()); + _metrics.Received(1).IncrementFailure(); } else { - _metrics.Verify(v => v.IncrementFailure(), Times.Never()); + _metrics.DidNotReceive().IncrementFailure(); } } [Fact] public void OnCircuitClosed_Ok() { - _metrics = new(MockBehavior.Loose, TimeProvider.System); + _metrics = Substitute.For(TimeProvider.System); var sut = Create(); sut.OnCircuitClosed(); - _metrics.Verify(v => v.Reset(), Times.Once()); + _metrics.Received(1).Reset(); } private AdvancedCircuitBehavior Create() { - return new AdvancedCircuitBehavior(CircuitBreakerConstants.DefaultFailureRatio, CircuitBreakerConstants.DefaultMinimumThroughput, _metrics.Object); + return new(CircuitBreakerConstants.DefaultFailureRatio, CircuitBreakerConstants.DefaultMinimumThroughput, _metrics); } } diff --git a/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs b/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs index 04115ef4224..41e0961b7ae 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Time.Testing; -using Moq; +using NSubstitute; using Polly.CircuitBreaker; using Polly.Telemetry; @@ -10,7 +10,7 @@ public class CircuitStateControllerTests private readonly FakeTimeProvider _timeProvider = new(); private readonly CircuitBreakerStrategyOptions _options = new(); - private readonly Mock _circuitBehavior = new(MockBehavior.Strict); + private readonly CircuitBehavior _circuitBehavior = Substitute.For(); private readonly Action _onTelemetry = _ => { }; [Fact] @@ -56,9 +56,10 @@ public async Task IsolateAsync_Ok() outcome.Value.Exception.Should().BeOfType(); // now close it - _circuitBehavior.Setup(v => v.OnCircuitClosed()); await controller.CloseCircuitAsync(ResilienceContextPool.Shared.Get()); await controller.OnActionPreExecuteAsync(ResilienceContextPool.Shared.Get()); + + _circuitBehavior.Received().OnCircuitClosed(); context.ResilienceEvents.Should().Contain(new ResilienceEvent(ResilienceEventSeverity.Error, "OnCircuitOpened")); } @@ -82,7 +83,6 @@ public async Task BreakAsync_Ok() _timeProvider.Advance(TimeSpan.FromSeconds(1)); using var controller = CreateController(); await controller.IsolateCircuitAsync(ResilienceContextPool.Shared.Get()); - _circuitBehavior.Setup(v => v.OnCircuitClosed()); var context = ResilienceContextPool.Shared.Get(); // act @@ -92,7 +92,7 @@ public async Task BreakAsync_Ok() called.Should().BeTrue(); await controller.OnActionPreExecuteAsync(ResilienceContextPool.Shared.Get()); - _circuitBehavior.VerifyAll(); + _circuitBehavior.Received().OnCircuitClosed(); context.ResilienceEvents.Should().Contain(new ResilienceEvent(ResilienceEventSeverity.Information, "OnCircuitClosed")); } @@ -146,18 +146,19 @@ public async Task HalfOpen_EnsureCorrectStateTransitionAfterExecution(bool succe if (success) { - _circuitBehavior.Setup(v => v.OnActionSuccess(CircuitState.HalfOpen)); - _circuitBehavior.Setup(v => v.OnCircuitClosed()); - await controller.OnActionSuccessAsync(Outcome.FromResult(0), ResilienceContextPool.Shared.Get()); controller.CircuitState.Should().Be(CircuitState.Closed); + + _circuitBehavior.Received().OnActionSuccess(CircuitState.HalfOpen); + _circuitBehavior.Received().OnCircuitClosed(); } else { - var shouldBreak = true; - _circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.HalfOpen, out shouldBreak)); await controller.OnActionFailureAsync(Outcome.FromResult(0), ResilienceContextPool.Shared.Get()); controller.CircuitState.Should().Be(CircuitState.Open); + + _circuitBehavior.DidNotReceiveWithAnyArgs().OnActionSuccess(default); + _circuitBehavior.Received().OnActionFailure(CircuitState.HalfOpen, out _); } } @@ -180,7 +181,7 @@ public async Task OnActionFailure_EnsureLock() AdvanceTime(_options.BreakDuration); bool shouldBreak = false; - _circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.Closed, out shouldBreak)).Callback(() => + _circuitBehavior.When(v => v.OnActionFailure(CircuitState.Closed, out shouldBreak)).Do((_) => { executing.Set(); verified.WaitOne(); @@ -245,21 +246,16 @@ public async Task OnActionSuccess_EnsureCorrectBehavior(CircuitState state, Circ await TransitionToState(controller, state); - _circuitBehavior.Setup(v => v.OnActionSuccess(state)); - if (expectedState == CircuitState.Closed && state != CircuitState.Closed) - { - _circuitBehavior.Setup(v => v.OnCircuitClosed()); - } - // act await controller.OnActionSuccessAsync(Outcome.FromResult(10), ResilienceContextPool.Shared.Get()); // assert controller.CircuitState.Should().Be(expectedState); - _circuitBehavior.VerifyAll(); + _circuitBehavior.Received().OnActionSuccess(state); if (expectedState == CircuitState.Closed && state != CircuitState.Closed) { + _circuitBehavior.Received().OnCircuitClosed(); called.Should().BeTrue(); } } @@ -291,7 +287,9 @@ public async Task OnActionFailureAsync_EnsureCorrectBehavior(CircuitState state, using var controller = CreateController(); await TransitionToState(controller, state); - _circuitBehavior.Setup(v => v.OnActionFailure(state, out shouldBreak)); + + _circuitBehavior.When(x => x.OnActionFailure(state, out Arg.Any())) + .Do(x => x[1] = shouldBreak); // act await controller.OnActionFailureAsync(Outcome.FromResult(99), ResilienceContextPool.Shared.Get()); @@ -299,7 +297,7 @@ public async Task OnActionFailureAsync_EnsureCorrectBehavior(CircuitState state, // assert controller.LastHandledOutcome!.Value.Result.Should().Be(99); controller.CircuitState.Should().Be(expectedState); - _circuitBehavior.VerifyAll(); + _circuitBehavior.Received().OnActionFailure(state, out Arg.Any()); if (expectedState == CircuitState.Open && state != CircuitState.Open) { @@ -324,7 +322,8 @@ public async Task OnActionFailureAsync_EnsureBreakDurationNotOverflow(bool overf _timeProvider.SetUtcNow(utcNow); - _circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.HalfOpen, out shouldBreak)); + _circuitBehavior.When(v => v.OnActionFailure(CircuitState.HalfOpen, out Arg.Any())) + .Do(x => x[1] = shouldBreak); // act await controller.OnActionFailureAsync(Outcome.FromResult(99), ResilienceContextPool.Shared.Get()); @@ -349,7 +348,9 @@ public async Task OnActionFailureAsync_VoidResult_EnsureBreakingExceptionNotSet( using var controller = CreateController(); bool shouldBreak = true; await TransitionToState(controller, CircuitState.Open); - _circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.Open, out shouldBreak)); + + _circuitBehavior.When(v => v.OnActionFailure(CircuitState.Open, out Arg.Any())) + .Do(x => x[1] = shouldBreak); // act await controller.OnActionFailureAsync(Outcome.FromResult(99), ResilienceContextPool.Shared.Get()); @@ -366,11 +367,12 @@ public async Task Flow_Closed_HalfOpen_Closed() using var controller = CreateController(); await TransitionToState(controller, CircuitState.HalfOpen); - _circuitBehavior.Setup(v => v.OnActionSuccess(CircuitState.HalfOpen)); - _circuitBehavior.Setup(v => v.OnCircuitClosed()); await controller.OnActionSuccessAsync(Outcome.FromResult(0), ResilienceContextPool.Shared.Get()); controller.CircuitState.Should().Be(CircuitState.Closed); + + _circuitBehavior.Received().OnActionSuccess(CircuitState.HalfOpen); + _circuitBehavior.Received().OnCircuitClosed(); } [Fact] @@ -382,7 +384,9 @@ public async Task Flow_Closed_HalfOpen_Open_HalfOpen_Closed() await TransitionToState(controller, CircuitState.HalfOpen); - _circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.HalfOpen, out shouldBreak)); + _circuitBehavior.When(v => v.OnActionFailure(CircuitState.HalfOpen, out Arg.Any())) + .Do(x => x[1] = shouldBreak); + await controller.OnActionFailureAsync(Outcome.FromResult(0), context); controller.CircuitState.Should().Be(CircuitState.Open); @@ -397,10 +401,11 @@ public async Task Flow_Closed_HalfOpen_Open_HalfOpen_Closed() controller.CircuitState.Should().Be(CircuitState.HalfOpen); // close circuit - _circuitBehavior.Setup(v => v.OnActionSuccess(CircuitState.HalfOpen)); - _circuitBehavior.Setup(v => v.OnCircuitClosed()); await controller.OnActionSuccessAsync(Outcome.FromResult(0), ResilienceContextPool.Shared.Get()); controller.CircuitState.Should().Be(CircuitState.Closed); + + _circuitBehavior.Received().OnActionSuccess(CircuitState.HalfOpen); + _circuitBehavior.Received().OnCircuitClosed(); } [Fact] @@ -446,7 +451,10 @@ private async Task TransitionToState(CircuitStateController controller, Cir private async Task OpenCircuit(CircuitStateController controller, Outcome? outcome = null) { bool breakCircuit = true; - _circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.Closed, out breakCircuit)); + + _circuitBehavior.When(v => v.OnActionFailure(CircuitState.Closed, out Arg.Any())) + .Do(x => x[1] = breakCircuit); + await controller.OnActionFailureAsync(outcome ?? Outcome.FromResult(10), ResilienceContextPool.Shared.Get().Initialize(true)); } @@ -457,7 +465,7 @@ private async Task OpenCircuit(CircuitStateController controller, Outcome(), () => 1.0); + var context = new StrategyBuilderContext("builder-name", "instance", properties, "strategy-name", timeProvider, Substitute.For(), () => 1.0); context.BuilderName.Should().Be("builder-name"); context.BuilderInstanceName.Should().Be("instance"); diff --git a/test/Polly.Core.Tests/CompositeStrategyBuilderTests.cs b/test/Polly.Core.Tests/CompositeStrategyBuilderTests.cs index 3462bab7aa2..2ef3d786dc6 100644 --- a/test/Polly.Core.Tests/CompositeStrategyBuilderTests.cs +++ b/test/Polly.Core.Tests/CompositeStrategyBuilderTests.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.Time.Testing; -using Moq; +using NSubstitute; using Polly.Retry; using Polly.Utils; @@ -24,10 +24,10 @@ public void CopyCtor_Ok() { var builder = new CompositeStrategyBuilder { - TimeProvider = Mock.Of(), + TimeProvider = Substitute.For(), Name = "dummy", Randomizer = () => 0.0, - DiagnosticSource = Mock.Of(), + DiagnosticSource = Substitute.For(), OnCreatingStrategy = _ => { }, }; diff --git a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index d9467bc87ef..6ef57f1e4b2 100644 --- a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -1,6 +1,6 @@ using FluentAssertions.Execution; using Microsoft.Extensions.Time.Testing; -using Moq; +using NSubstitute; using Polly.Retry; using Polly.Telemetry; using Polly.Utils; @@ -11,12 +11,12 @@ public class RetryResilienceStrategyTests { private readonly RetryStrategyOptions _options = new(); private readonly FakeTimeProvider _timeProvider = new(); - private readonly Mock _diagnosticSource = new(); + private readonly DiagnosticSource _diagnosticSource = Substitute.For(); private ResilienceStrategyTelemetry _telemetry; public RetryResilienceStrategyTests() { - _telemetry = TestUtilities.CreateResilienceTelemetry(_diagnosticSource.Object); + _telemetry = TestUtilities.CreateResilienceTelemetry(_diagnosticSource); _options.ShouldHandle = _ => new ValueTask(false); } @@ -290,7 +290,7 @@ public async Task OnRetry_EnsureTelemetry() var attempts = new List(); var delays = new List(); - _diagnosticSource.Setup(v => v.IsEnabled("OnRetry")).Returns(true); + _diagnosticSource.IsEnabled("OnRetry").Returns(true); _options.ShouldHandle = args => args.Outcome.ResultPredicateAsync(0); _options.RetryCount = 3; @@ -300,7 +300,7 @@ public async Task OnRetry_EnsureTelemetry() await ExecuteAndAdvance(sut); - _diagnosticSource.VerifyAll(); + _diagnosticSource.Received(3).IsEnabled("OnRetry"); } [Fact] diff --git a/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs b/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs index 22a736bf9d5..446418be4e9 100644 --- a/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs +++ b/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs @@ -1,30 +1,30 @@ -using Moq; +using NSubstitute; using Polly.Telemetry; namespace Polly.Core.Tests.Telemetry; public class ResilienceStrategyTelemetryTests { - private readonly Mock _diagnosticSource = new(MockBehavior.Strict); + private readonly DiagnosticSource _diagnosticSource = Substitute.For(); public ResilienceStrategyTelemetryTests() => _sut = new(new ResilienceTelemetrySource( "builder", "instance", new ResilienceProperties(), - "strategy-name"), _diagnosticSource.Object); + "strategy-name"), _diagnosticSource); private readonly ResilienceStrategyTelemetry _sut; [Fact] public void Report_NoOutcome_OK() { - _diagnosticSource.Setup(o => o.IsEnabled("dummy-event")).Returns(true); + _diagnosticSource.IsEnabled("dummy-event").Returns(true); _diagnosticSource - .Setup(o => o.Write("dummy-event", It.Is(obj => obj is TelemetryEventArguments))) - .Callback((_, obj) => + .When(o => o.Write("dummy-event", Arg.Is(obj => obj is TelemetryEventArguments))) + .Do((p) => { - obj.Should().BeOfType(); - var args = (TelemetryEventArguments)obj; + p[1].Should().BeOfType(); + var args = (TelemetryEventArguments)p[1]; args.Event.EventName.Should().Be("dummy-event"); args.Event.Severity.Should().Be(ResilienceEventSeverity.Warning); @@ -38,18 +38,17 @@ public void Report_NoOutcome_OK() _sut.Report(new(ResilienceEventSeverity.Warning, "dummy-event"), ResilienceContextPool.Shared.Get(), new TestArguments()); - _diagnosticSource.VerifyAll(); + _diagnosticSource.Received().Write("dummy-event", Arg.Is(obj => obj is TelemetryEventArguments)); } [Fact] public void Report_NoOutcomeWhenNotSubscribed_None() { - _diagnosticSource.Setup(o => o.IsEnabled("dummy-event")).Returns(false); + _diagnosticSource.IsEnabled("dummy-event").Returns(false); _sut.Report(new(ResilienceEventSeverity.Warning, "dummy-event"), ResilienceContextPool.Shared.Get(), new TestArguments()); - _diagnosticSource.VerifyAll(); - _diagnosticSource.VerifyNoOtherCalls(); + _diagnosticSource.DidNotReceiveWithAnyArgs().Write(default!, default); } [Fact] @@ -66,13 +65,13 @@ public void ResilienceStrategyTelemetry_NoDiagnosticSource_Ok() [Fact] public void Report_Outcome_OK() { - _diagnosticSource.Setup(o => o.IsEnabled("dummy-event")).Returns(true); + _diagnosticSource.IsEnabled("dummy-event").Returns(true); _diagnosticSource - .Setup(o => o.Write("dummy-event", It.Is(obj => obj is TelemetryEventArguments))) - .Callback((_, obj) => + .When(o => o.Write("dummy-event", Arg.Is(obj => obj is TelemetryEventArguments))) + .Do((obj) => { - obj.Should().BeOfType(); - var args = (TelemetryEventArguments)obj; + obj[1].Should().BeOfType(); + var args = (TelemetryEventArguments)obj[1]; args.Event.EventName.Should().Be("dummy-event"); args.Event.Severity.Should().Be(ResilienceEventSeverity.Warning); @@ -87,30 +86,28 @@ public void Report_Outcome_OK() var context = ResilienceContextPool.Shared.Get(); _sut.Report(new(ResilienceEventSeverity.Warning, "dummy-event"), new OutcomeArguments(context, Outcome.FromResult(99), new TestArguments())); - _diagnosticSource.VerifyAll(); + _diagnosticSource.Received().Write("dummy-event", Arg.Is(obj => obj is TelemetryEventArguments)); } [Fact] public void Report_SeverityNone_Skipped() { - _diagnosticSource.Setup(o => o.IsEnabled("dummy-event")).Returns(true); + _diagnosticSource.IsEnabled("dummy-event").Returns(true); var context = ResilienceContextPool.Shared.Get(); _sut.Report(new(ResilienceEventSeverity.None, "dummy-event"), new OutcomeArguments(context, Outcome.FromResult(99), new TestArguments())); _sut.Report(new(ResilienceEventSeverity.None, "dummy-event"), ResilienceContextPool.Shared.Get(), new TestArguments()); - _diagnosticSource.VerifyAll(); - _diagnosticSource.VerifyNoOtherCalls(); + _diagnosticSource.DidNotReceiveWithAnyArgs().Write(default!, default); } [Fact] public void Report_OutcomeWhenNotSubscribed_None() { - _diagnosticSource.Setup(o => o.IsEnabled("dummy-event")).Returns(false); + _diagnosticSource.IsEnabled("dummy-event").Returns(false); var context = ResilienceContextPool.Shared.Get(); _sut.Report(new(ResilienceEventSeverity.Warning, "dummy-event"), new OutcomeArguments(context, Outcome.FromResult(10), new TestArguments())); - _diagnosticSource.VerifyAll(); - _diagnosticSource.VerifyNoOtherCalls(); + _diagnosticSource.DidNotReceiveWithAnyArgs().Write(default!, default); } } diff --git a/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs b/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs index fd138a72a48..67e13f4e3f4 100644 --- a/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs +++ b/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs @@ -1,4 +1,4 @@ -using Moq; +using NSubstitute; using Polly.Telemetry; namespace Polly.Core.Tests.Telemetry; @@ -20,7 +20,7 @@ public void CreateResilienceTelemetry_Ok() public void CreateResilienceTelemetry_DiagnosticSourceFromProperties_Ok() { var props = new ResilienceProperties(); - var source = Mock.Of(); + var source = Substitute.For(); var telemetry = TelemetryUtil.CreateTelemetry(source, "builder", "instance", props, "strategy-name"); diff --git a/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs b/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs index 72b423b7ea4..978bdfb199a 100644 --- a/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Time.Testing; -using Moq; +using NSubstitute; using Polly.Telemetry; using Polly.Timeout; @@ -13,11 +13,11 @@ public class TimeoutResilienceStrategyTests : IDisposable private readonly CancellationTokenSource _cancellationSource; private readonly TimeSpan _delay = TimeSpan.FromSeconds(12); - private readonly Mock _diagnosticSource = new(); + private readonly DiagnosticSource _diagnosticSource = Substitute.For(); public TimeoutResilienceStrategyTests() { - _telemetry = TestUtilities.CreateResilienceTelemetry(_diagnosticSource.Object); + _telemetry = TestUtilities.CreateResilienceTelemetry(_diagnosticSource); _options = new TimeoutStrategyOptions(); _cancellationSource = new CancellationTokenSource(); } @@ -52,7 +52,7 @@ public void Execute_EnsureTimeoutGeneratorCalled() [Fact] public async Task Execute_EnsureOnTimeoutCalled() { - _diagnosticSource.Setup(v => v.IsEnabled("OnTimeout")).Returns(true); + _diagnosticSource.IsEnabled("OnTimeout").Returns(true); var called = false; SetTimeout(_delay); @@ -78,7 +78,7 @@ await sut.Invoking(s => sut.ExecuteAsync(async token => .AsTask()).Should().ThrowAsync(); called.Should().BeTrue(); - _diagnosticSource.VerifyAll(); + _diagnosticSource.Received().IsEnabled("OnTimeout"); } [MemberData(nameof(Execute_NoTimeout_Data))] @@ -164,7 +164,7 @@ await sut.Invoking(s => s.ExecuteAsync(async token => onTimeoutCalled.Should().BeFalse(); - _diagnosticSource.Verify(v => v.IsEnabled("OnTimeout"), Times.Never()); + _diagnosticSource.DidNotReceive().IsEnabled("OnTimeout"); } [Fact] @@ -202,16 +202,15 @@ public async Task Execute_EnsureCancellationTokenRegistrationNotExecutedOnSynchr var sut = CreateSut(); - var mockSynchronizationContext = new Mock(MockBehavior.Strict); + var mockSynchronizationContext = Substitute.For(); mockSynchronizationContext - .Setup(x => x.Post(It.IsAny(), It.IsAny())) - .Callback((callback, state) => callback(state)); + .When(x => x.Post(Arg.Any(), Arg.Any())) + .Do((p) => ((SendOrPostCallback)p[1])(p[2])); - mockSynchronizationContext - .Setup(x => x.CreateCopy()) - .Returns(mockSynchronizationContext.Object); + mockSynchronizationContext.CreateCopy() + .Returns(mockSynchronizationContext); - SynchronizationContext.SetSynchronizationContext(mockSynchronizationContext.Object); + SynchronizationContext.SetSynchronizationContext(mockSynchronizationContext); // Act try @@ -230,7 +229,7 @@ await sut.ExecuteAsync(async token => } // Assert - mockSynchronizationContext.Verify(x => x.Post(It.IsAny(), It.IsAny()), Times.Never()); + mockSynchronizationContext.DidNotReceiveWithAnyArgs().Post(default!, default); } private void SetTimeout(TimeSpan timeout) => _options.TimeoutGenerator = args => new ValueTask(timeout); diff --git a/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs b/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs index 75fe6db8077..44e2433cb5e 100644 --- a/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs +++ b/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Time.Testing; -using Moq; using Polly.Utils; namespace Polly.Core.Tests.Utils; @@ -93,9 +92,5 @@ public async Task Rent_NotCancellable_EnsureNotCancelled(object timeProvider) cts.IsCancellationRequested.Should().BeFalse(); } - private static TimeProvider GetTimeProvider(object timeProvider) => timeProvider switch - { - Mock m => m.Object, - _ => (TimeProvider)timeProvider - }; + private static TimeProvider GetTimeProvider(object timeProvider) => (TimeProvider)timeProvider; } diff --git a/test/Polly.Core.Tests/Utils/DisposeHelperTests.cs b/test/Polly.Core.Tests/Utils/DisposeHelperTests.cs index c7795f003ad..f149b35f4b2 100644 --- a/test/Polly.Core.Tests/Utils/DisposeHelperTests.cs +++ b/test/Polly.Core.Tests/Utils/DisposeHelperTests.cs @@ -1,4 +1,4 @@ -using Moq; +using NSubstitute; using Polly.Utils; namespace Polly.Core.Tests.Utils; @@ -28,11 +28,13 @@ public async Task Dispose_Disposable_Ok(bool synchronous) [Theory] public async Task Dispose_AsyncDisposable_Ok(bool synchronous) { - var disposable = new Mock(); + var disposable = Substitute.For(); bool disposed = false; - disposable.Setup(v => v.DisposeAsync()).Returns(default(ValueTask)).Callback(() => disposed = true); - await DisposeHelper.TryDisposeSafeAsync(disposable.Object, synchronous); + disposable.When(async (p) => await p.DisposeAsync()) + .Do((_) => disposed = true); + + await DisposeHelper.TryDisposeSafeAsync(disposable, synchronous); disposed.Should().BeTrue(); } @@ -42,10 +44,10 @@ public async Task Dispose_AsyncDisposable_Ok(bool synchronous) [Theory] public async Task Dispose_DisposeThrows_ExceptionHandled(bool synchronous) { - var disposable = new Mock(); - disposable.Setup(v => v.DisposeAsync()).Throws(new InvalidOperationException()); + var disposable = Substitute.For(); + disposable.When(async v => await v.DisposeAsync()).Do((_) => throw new InvalidOperationException()); - await disposable.Object.Invoking(async _ => await DisposeHelper.TryDisposeSafeAsync(disposable.Object, synchronous)).Should().NotThrowAsync(); + await disposable.Invoking(async _ => await DisposeHelper.TryDisposeSafeAsync(disposable, synchronous)).Should().NotThrowAsync(); } [InlineData(true)] diff --git a/test/Polly.Extensions.Tests/Utils/OptionsReloadHelperTests.cs b/test/Polly.Extensions.Tests/Utils/OptionsReloadHelperTests.cs index e0717cf976a..bc410917824 100644 --- a/test/Polly.Extensions.Tests/Utils/OptionsReloadHelperTests.cs +++ b/test/Polly.Extensions.Tests/Utils/OptionsReloadHelperTests.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Options; -using Moq; +using NSubstitute; using Polly.Utils; namespace Polly.Extensions.Tests.Utils; @@ -9,14 +9,14 @@ public class OptionsReloadHelperTests [Fact] public void Ctor_NamedOptions() { - var monitor = new Mock>(); + var disposable = Substitute.For(); + var monitor = Substitute.For>(); - monitor - .Setup(m => m.OnChange(It.IsAny>())) - .Returns(() => Mock.Of()); + monitor.OnChange(Arg.Any>()) + .Returns(disposable); - var helper = new OptionsReloadHelper(monitor.Object, "name"); + var helper = new OptionsReloadHelper(monitor, "name"); - monitor.VerifyAll(); + monitor.Received().OnChange(Arg.Any>()); } } diff --git a/test/Polly.RateLimiting.Tests/OnRateLimiterRejectedArgumentsTests.cs b/test/Polly.RateLimiting.Tests/OnRateLimiterRejectedArgumentsTests.cs index 40dddb1032c..002793435c8 100644 --- a/test/Polly.RateLimiting.Tests/OnRateLimiterRejectedArgumentsTests.cs +++ b/test/Polly.RateLimiting.Tests/OnRateLimiterRejectedArgumentsTests.cs @@ -1,5 +1,5 @@ using System.Threading.RateLimiting; -using Moq; +using NSubstitute; namespace Polly.RateLimiting.Tests; @@ -8,7 +8,7 @@ public class OnRateLimiterRejectedArgumentsTests [Fact] public void Ctor_Ok() { - var args = new OnRateLimiterRejectedArguments(ResilienceContextPool.Shared.Get(), Mock.Of(), TimeSpan.FromSeconds(1)); + var args = new OnRateLimiterRejectedArguments(ResilienceContextPool.Shared.Get(), Substitute.For(), TimeSpan.FromSeconds(1)); args.Context.Should().NotBeNull(); args.Lease.Should().NotBeNull(); diff --git a/test/Polly.RateLimiting.Tests/RateLimiterCompositeStrategyBuilderExtensionsTests.cs b/test/Polly.RateLimiting.Tests/RateLimiterCompositeStrategyBuilderExtensionsTests.cs index 10e36ecf422..c9d6689d4dc 100644 --- a/test/Polly.RateLimiting.Tests/RateLimiterCompositeStrategyBuilderExtensionsTests.cs +++ b/test/Polly.RateLimiting.Tests/RateLimiterCompositeStrategyBuilderExtensionsTests.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.Threading.RateLimiting; -using Moq; +using NSubstitute; namespace Polly.RateLimiting.Tests; @@ -26,7 +26,7 @@ public class RateLimiterCompositeStrategyBuilderExtensionsTests }, builder => { - var expected = Mock.Of(); + var expected = Substitute.For(); builder.AddRateLimiter(expected); AssertRateLimiter(builder, hasEvents: false, limiter => limiter.Should().Be(expected)); } @@ -123,7 +123,7 @@ public void AddRateLimiter_Options_Ok() var strategy = new CompositeStrategyBuilder() .AddRateLimiter(new RateLimiterStrategyOptions { - RateLimiter = ResilienceRateLimiter.Create(Mock.Of()) + RateLimiter = ResilienceRateLimiter.Create(Substitute.For()) }) .Build(); @@ -139,7 +139,7 @@ private static void AssertRateLimiter(CompositeStrategyBuilder builder, boo { strategy.OnLeaseRejected.Should().NotBeNull(); strategy - .OnLeaseRejected!(new OnRateLimiterRejectedArguments(ResilienceContextPool.Shared.Get(), Mock.Of(), null)) + .OnLeaseRejected!(new OnRateLimiterRejectedArguments(ResilienceContextPool.Shared.Get(), Substitute.For(), null)) .Preserve().GetAwaiter().GetResult(); } else @@ -159,7 +159,7 @@ private static void AssertConcurrencyLimiter(CompositeStrategyBuilder build { strategy.OnLeaseRejected.Should().NotBeNull(); strategy - .OnLeaseRejected!(new OnRateLimiterRejectedArguments(ResilienceContextPool.Shared.Get(), Mock.Of(), null)) + .OnLeaseRejected!(new OnRateLimiterRejectedArguments(ResilienceContextPool.Shared.Get(), Substitute.For(), null)) .Preserve().GetAwaiter().GetResult(); } else diff --git a/test/Polly.RateLimiting.Tests/RateLimiterResilienceStrategyTests.cs b/test/Polly.RateLimiting.Tests/RateLimiterResilienceStrategyTests.cs index 53763ece911..1dae568a25e 100644 --- a/test/Polly.RateLimiting.Tests/RateLimiterResilienceStrategyTests.cs +++ b/test/Polly.RateLimiting.Tests/RateLimiterResilienceStrategyTests.cs @@ -1,14 +1,13 @@ using System.Threading.RateLimiting; -using Moq; -using Moq.Protected; +using NSubstitute; namespace Polly.RateLimiting.Tests; public class RateLimiterResilienceStrategyTests { - private readonly Mock _limiter = new(MockBehavior.Strict); - private readonly Mock _lease = new(MockBehavior.Strict); - private readonly Mock _diagnosticSource = new(); + private readonly RateLimiter _limiter = Substitute.For(); + private readonly RateLimitLease _lease = Substitute.For(); + private readonly DiagnosticSource _diagnosticSource = Substitute.For(); private Func? _event; [Fact] @@ -18,14 +17,13 @@ public void Ctor_Ok() } [Fact] - public void Execute_HappyPath() + public async Task Execute_HappyPath() { using var cts = new CancellationTokenSource(); SetupLimiter(cts.Token); - _lease.Setup(v => v.IsAcquired).Returns(true); - _lease.Protected().Setup("Dispose", exactParameterMatch: true, true); + _lease.IsAcquired.Returns(true); Create().Should().NotBeNull(); @@ -33,8 +31,8 @@ public void Execute_HappyPath() strategy.Execute(_ => { }, cts.Token); - _limiter.VerifyAll(); - _lease.VerifyAll(); + await _limiter.ReceivedWithAnyArgs().AcquireAsync(default, default); + _lease.Received().Dispose(); } [InlineData(false, true)] @@ -44,8 +42,8 @@ public void Execute_HappyPath() [Theory] public async Task Execute_LeaseRejected(bool hasEvents, bool hasRetryAfter) { - _diagnosticSource.Setup(v => v.IsEnabled("OnRateLimiterRejected")).Returns(true); - _diagnosticSource.Setup(v => v.Write("OnRateLimiterRejected", It.Is(obj => obj != null))); + _diagnosticSource.IsEnabled("OnRateLimiterRejected").Returns(true); + _diagnosticSource.Write("OnRateLimiterRejected", Arg.Is(obj => obj != null)); object? metadata = hasRetryAfter ? TimeSpan.FromSeconds(123) : null; @@ -53,16 +51,20 @@ public async Task Execute_LeaseRejected(bool hasEvents, bool hasRetryAfter) var eventCalled = false; SetupLimiter(cts.Token); - _lease.Setup(v => v.IsAcquired).Returns(false); - _lease.Protected().Setup("Dispose", exactParameterMatch: true, true); - _lease.Setup(v => v.TryGetMetadata("RETRY_AFTER", out metadata)).Returns(hasRetryAfter); + _lease.IsAcquired.Returns(false); + _lease.TryGetMetadata("RETRY_AFTER", out Arg.Any()) + .Returns(x => + { + x[1] = hasRetryAfter ? metadata : null; + return hasRetryAfter; + }); if (hasEvents) { _event = args => { args.Context.Should().NotBeNull(); - args.Lease.Should().Be(_lease.Object); + args.Lease.Should().Be(_lease); args.RetryAfter.Should().Be((TimeSpan?)metadata); eventCalled = true; return default; @@ -81,29 +83,33 @@ public async Task Execute_LeaseRejected(bool hasEvents, bool hasRetryAfter) outcome.Exception!.StackTrace.Should().Contain("Execute_LeaseRejected"); - _limiter.VerifyAll(); - _lease.VerifyAll(); eventCalled.Should().Be(hasEvents); - _diagnosticSource.VerifyAll(); + await _limiter.ReceivedWithAnyArgs().AcquireAsync(default, default); + _lease.Received().Dispose(); } - private void SetupLimiter(CancellationToken token) => _limiter - .Protected() - .Setup>("AcquireAsyncCore", 1, token) - .Returns(new ValueTask(_lease.Object)); + private void SetupLimiter(CancellationToken token) + { + var result = new ValueTask(_lease); + _limiter + .GetType() + .GetMethod("AcquireAsyncCore", BindingFlags.NonPublic | BindingFlags.Instance)! + .Invoke(_limiter, new object[] { 1, token }) + .Returns(result); + } private RateLimiterResilienceStrategy Create() { var builder = new CompositeStrategyBuilder { - DiagnosticSource = _diagnosticSource.Object + DiagnosticSource = _diagnosticSource }; return (RateLimiterResilienceStrategy)builder .AddRateLimiter(new RateLimiterStrategyOptions { - RateLimiter = ResilienceRateLimiter.Create(_limiter.Object), + RateLimiter = ResilienceRateLimiter.Create(_limiter), OnRejected = _event }) .Build(); diff --git a/test/Polly.RateLimiting.Tests/ResilienceRateLimiterTests.cs b/test/Polly.RateLimiting.Tests/ResilienceRateLimiterTests.cs index fd3ef8a31b4..439657c6620 100644 --- a/test/Polly.RateLimiting.Tests/ResilienceRateLimiterTests.cs +++ b/test/Polly.RateLimiting.Tests/ResilienceRateLimiterTests.cs @@ -1,6 +1,5 @@ using System.Threading.RateLimiting; -using Moq; -using Moq.Protected; +using NSubstitute; namespace Polly.RateLimiting.Tests; @@ -9,29 +8,40 @@ public class ResilienceRateLimiterTests [Fact] public async Task Create_RateLimiter_Ok() { - var lease = Mock.Of(); - var limiterMock = new Mock(MockBehavior.Strict); - limiterMock.Protected().Setup>("AcquireAsyncCore", 1, default(CancellationToken)).ReturnsAsync(lease); + var lease = Substitute.For(); + var leaseTask = new ValueTask(lease); - var limiter = ResilienceRateLimiter.Create(limiterMock.Object); + var rateLimiter = Substitute.For(); + rateLimiter + .GetType() + .GetMethod("AcquireAsyncCore", BindingFlags.NonPublic | BindingFlags.Instance)! + .Invoke(rateLimiter, new object[] { 1, default(CancellationToken) }) + .Returns(leaseTask); + + var limiter = ResilienceRateLimiter.Create(rateLimiter); (await limiter.AcquireAsync(ResilienceContextPool.Shared.Get())).Should().Be(lease); limiter.Limiter.Should().NotBeNull(); - limiterMock.VerifyAll(); } [Fact] public async Task Create_PartitionedRateLimiter_Ok() { var context = ResilienceContextPool.Shared.Get(); - var lease = Mock.Of(); - var limiterMock = new Mock>(MockBehavior.Strict); - limiterMock.Protected().Setup>("AcquireAsyncCore", context, 1, default(CancellationToken)).ReturnsAsync(lease); - var limiter = ResilienceRateLimiter.Create(limiterMock.Object); + var lease = Substitute.For(); + var leaseTask = new ValueTask(lease); + + var rateLimiter = Substitute.For>(); + rateLimiter + .GetType() + .GetMethod("AcquireAsyncCore", BindingFlags.NonPublic | BindingFlags.Instance)! + .Invoke(rateLimiter, new object[] { context, 1, default(CancellationToken) }) + .Returns(leaseTask); + + var limiter = ResilienceRateLimiter.Create(rateLimiter); (await limiter.AcquireAsync(context)).Should().Be(lease); limiter.PartitionedLimiter.Should().NotBeNull(); - limiterMock.VerifyAll(); } } diff --git a/test/Polly.Specs/Polly.Specs.csproj b/test/Polly.Specs/Polly.Specs.csproj index f0990bae0cc..9f173f8b1d6 100644 --- a/test/Polly.Specs/Polly.Specs.csproj +++ b/test/Polly.Specs/Polly.Specs.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/Polly.Specs/Registry/PolicyRegistrySpecs.cs b/test/Polly.Specs/Registry/PolicyRegistrySpecs.cs index b1e0d5c478f..1fd8f1fed04 100644 --- a/test/Polly.Specs/Registry/PolicyRegistrySpecs.cs +++ b/test/Polly.Specs/Registry/PolicyRegistrySpecs.cs @@ -442,13 +442,13 @@ public void Should_throw_when_checking_if_key_exists_when_key_is_null() [Fact] public void Constructor_Called_With_A_Registry_Parameter_Should_Assign_The_Passed_In_Registry_To_The_Registry_Field() { - var testDictionary = new Mock>(); - var testRegistry = new PolicyRegistry(testDictionary.Object); + var testDictionary = Substitute.For>(); + var testRegistry = new PolicyRegistry(testDictionary); // Generally, using reflection is a bad practice, but we are accepting it given we own the implementation. var registryField = typeof(PolicyRegistry).GetField("_registry", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance)!; var registryFieldValue = registryField.GetValue(testRegistry); - registryFieldValue.Should().Be(testDictionary.Object); + registryFieldValue.Should().Be(testDictionary); } [Fact] diff --git a/test/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs b/test/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs index 029ccaa812b..09a09496f7d 100644 --- a/test/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs +++ b/test/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs @@ -256,12 +256,12 @@ public void Should_throw_when_checking_if_key_exists_when_key_is_null() [Fact] public void Calling_The_GetEnumerator_Method_Returning_A_IEnumerator_Of_KeyValuePair_Of_String_And_IsPolicy_Calls_The_Registrys_GetEnumerator_Method() { - var testDictionary = new Mock>(); - var testRegistry = new PolicyRegistry(testDictionary.Object); + var testDictionary = Substitute.For>(); + var testRegistry = new PolicyRegistry(testDictionary); testRegistry.GetEnumerator(); - testDictionary.Verify(x => x.GetEnumerator(), Times.Once); + testDictionary.Received(1).GetEnumerator(); } #endregion diff --git a/test/Polly.TestUtils/Polly.TestUtils.csproj b/test/Polly.TestUtils/Polly.TestUtils.csproj index a8bdb89c1cd..e47d1495b74 100644 --- a/test/Polly.TestUtils/Polly.TestUtils.csproj +++ b/test/Polly.TestUtils/Polly.TestUtils.csproj @@ -13,6 +13,6 @@ - + diff --git a/test/Polly.TestUtils/TestUtilities.cs b/test/Polly.TestUtils/TestUtilities.cs index 763eb1758fa..2e8d783958e 100644 --- a/test/Polly.TestUtils/TestUtilities.cs +++ b/test/Polly.TestUtils/TestUtilities.cs @@ -1,6 +1,6 @@ using System.Diagnostics.Metrics; using Microsoft.Extensions.Logging; -using Moq; +using NSubstitute; using Polly.Telemetry; namespace Polly.TestUtils; @@ -46,11 +46,10 @@ public static ResilienceStrategyTelemetry CreateResilienceTelemetry(Action(MockBehavior.Strict); - loggerFactory.Setup(v => v.CreateLogger("Polly")).Returns(logger); - loggerFactory.Setup(v => v.Dispose()); + var loggerFactory = Substitute.For(); + loggerFactory.CreateLogger("Polly").Returns(logger); - return loggerFactory.Object; + return loggerFactory; } public static IDisposable EnablePollyMetering(ICollection events)