From 7e53a5eedca3cb3cba7742e13a4e118da50f2aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <2493377+askpt@users.noreply.github.com> Date: Wed, 6 Sep 2023 12:56:06 +0100 Subject: [PATCH] test: Remove Moq (#79) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Silva <2493377+askpt@users.noreply.github.com> Signed-off-by: Vladimir Petrusevici --- build/Common.tests.props | 4 +- .../FlagdProviderTest.cs | 215 +++++++++--------- .../HttpClientMock.cs | 34 --- 3 files changed, 104 insertions(+), 149 deletions(-) delete mode 100644 test/OpenFeature.Contrib.Providers.GOFeatureFlag.Test/HttpClientMock.cs diff --git a/build/Common.tests.props b/build/Common.tests.props index 71b4578e..8a533a23 100644 --- a/build/Common.tests.props +++ b/build/Common.tests.props @@ -29,7 +29,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -46,7 +46,7 @@ [3.1.2] [6.7.0] [17.3.2] - [4.18.2] + [5.0.0] [2.4.3,3.0) [2.4.1,3.0) diff --git a/test/OpenFeature.Contrib.Providers.Flagd.Test/FlagdProviderTest.cs b/test/OpenFeature.Contrib.Providers.Flagd.Test/FlagdProviderTest.cs index e1115505..caf3de18 100644 --- a/test/OpenFeature.Contrib.Providers.Flagd.Test/FlagdProviderTest.cs +++ b/test/OpenFeature.Contrib.Providers.Flagd.Test/FlagdProviderTest.cs @@ -1,5 +1,4 @@ using Xunit; -using Moq; using OpenFeature.Flagd.Grpc; using Grpc.Core; using Google.Protobuf.WellKnownTypes; @@ -9,6 +8,7 @@ using OpenFeature.Model; using System.Threading; using System; +using NSubstitute; namespace OpenFeature.Contrib.Providers.Flagd.Test { @@ -120,8 +120,10 @@ public void TestGetProviderWithConfig() [Fact] public void TestResolveBooleanValue() { - var resp = new ResolveBooleanResponse(); - resp.Value = true; + var resp = new ResolveBooleanResponse + { + Value = true + }; var grpcResp = new AsyncUnaryCall( System.Threading.Tasks.Task.FromResult(resp), @@ -130,13 +132,13 @@ public void TestResolveBooleanValue() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var substituteGrpcClient = Substitute.For(); + substituteGrpcClient + .ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(substituteGrpcClient, new FlagdConfig()); // resolve with default set to false to make sure we return what the grpc server gives us var val = flagdProvider.ResolveBooleanValue("my-key", false, null); @@ -147,8 +149,7 @@ public void TestResolveBooleanValue() [Fact] public void TestResolveStringValue() { - var resp = new ResolveStringResponse(); - resp.Value = "my-value"; + var resp = new ResolveStringResponse { Value = "my-value" }; var grpcResp = new AsyncUnaryCall( System.Threading.Tasks.Task.FromResult(resp), @@ -157,13 +158,13 @@ public void TestResolveStringValue() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveStringAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var subGrpcClient = Substitute.For(); + + subGrpcClient.ResolveStringAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(subGrpcClient, new FlagdConfig()); var val = flagdProvider.ResolveStringValue("my-key", "", null); @@ -173,8 +174,10 @@ public void TestResolveStringValue() [Fact] public void TestResolveIntegerValue() { - var resp = new ResolveIntResponse(); - resp.Value = 10; + var resp = new ResolveIntResponse + { + Value = 10 + }; var grpcResp = new AsyncUnaryCall( System.Threading.Tasks.Task.FromResult(resp), @@ -183,13 +186,11 @@ public void TestResolveIntegerValue() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveIntAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var subGrpcClient = Substitute.For(); + subGrpcClient.ResolveIntAsync(Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(subGrpcClient, new FlagdConfig()); var val = flagdProvider.ResolveIntegerValue("my-key", 0, null); @@ -199,8 +200,10 @@ public void TestResolveIntegerValue() [Fact] public void TestResolveDoubleValue() { - var resp = new ResolveFloatResponse(); - resp.Value = 10.0; + var resp = new ResolveFloatResponse + { + Value = 10.0 + }; var grpcResp = new AsyncUnaryCall( System.Threading.Tasks.Task.FromResult(resp), @@ -209,13 +212,11 @@ public void TestResolveDoubleValue() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveFloatAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveFloatAsync(Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(mockGrpcClient, new FlagdConfig()); var val = flagdProvider.ResolveDoubleValue("my-key", 0.0, null); @@ -240,13 +241,11 @@ public void TestResolveStructureValue() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveObjectAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveObjectAsync(Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(mockGrpcClient, new FlagdConfig()); var val = flagdProvider.ResolveStructureValue("my-key", null, null); @@ -265,13 +264,11 @@ public void TestResolveFlagNotFound() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) - .Returns(grpcResp); + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None).Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(mockGrpcClient, new FlagdConfig()); // make sure the correct exception is thrown Assert.ThrowsAsync(async () => @@ -301,13 +298,12 @@ public void TestResolveGrpcHostUnavailable() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(mockGrpcClient, new FlagdConfig()); // make sure the correct exception is thrown Assert.ThrowsAsync(async () => @@ -337,13 +333,12 @@ public void TestResolveTypeMismatch() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(mockGrpcClient, new FlagdConfig()); // make sure the correct exception is thrown Assert.ThrowsAsync(async () => @@ -373,13 +368,12 @@ public void TestResolveUnknownError() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, new FlagdConfig()); + var flagdProvider = new FlagdProvider(mockGrpcClient, new FlagdConfig()); // make sure the correct exception is thrown Assert.ThrowsAsync(async () => @@ -411,13 +405,12 @@ public void TestCache() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var asyncStreamReader = new Mock>(); + var asyncStreamReader = Substitute.For>(); var l = new List { @@ -431,8 +424,8 @@ public void TestCache() // create an autoResetEvent which we will wait for in our test verification var _autoResetEvent = new AutoResetEvent(false); - asyncStreamReader.Setup(a => a.MoveNext(It.IsAny())).ReturnsAsync(() => enumerator.MoveNext()); - asyncStreamReader.Setup(a => a.Current).Returns(() => + asyncStreamReader.MoveNext(Arg.Any()).Returns(enumerator.MoveNext()); + asyncStreamReader.Current.Returns(_ => { // set the autoResetEvent since this path should be the last one that's reached in the background task _autoResetEvent.Set(); @@ -440,7 +433,7 @@ public void TestCache() }); var grpcEventStreamResp = new AsyncServerStreamingCall( - asyncStreamReader.Object, + asyncStreamReader, null, null, null, @@ -448,37 +441,37 @@ public void TestCache() null ); - mockGrpcClient - .Setup(m => m.EventStream( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + mockGrpcClient.EventStream( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcEventStreamResp); - var mockCache = new Mock>(); - mockCache.Setup(c => c.TryGet(It.Is(s => s == "my-key"))).Returns(() => null); - mockCache.Setup(c => c.Add(It.Is(s => s == "my-key"), It.IsAny())); + var mockCache = Substitute.For>(); + mockCache.TryGet(Arg.Is(s => s == "my-key")).Returns(null); + mockCache.Add(Arg.Is(s => s == "my-key"), Arg.Any()); var config = new FlagdConfig(); config.CacheEnabled = true; config.MaxEventStreamRetries = 1; - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, config, mockCache.Object); + var flagdProvider = new FlagdProvider(mockGrpcClient, config, mockCache); // resolve with default set to false to make sure we return what the grpc server gives us var val = flagdProvider.ResolveBooleanValue("my-key", false, null); Assert.True(val.Result.Value); Assert.True(_autoResetEvent.WaitOne(10000)); - mockCache.VerifyAll(); - mockGrpcClient.VerifyAll(); + mockCache.Received(1).TryGet(Arg.Is(s => s == "my-key")); + mockCache.Received(1).Add(Arg.Is(s => s == "my-key"), Arg.Any()); + mockGrpcClient.Received(1).EventStream(Arg.Any(), null, null, System.Threading.CancellationToken.None); } [Fact] public void TestCacheHit() { - var mockGrpcClient = new Mock(); + var mockGrpcClient = Substitute.For(); - var asyncStreamReader = new Mock>(); + var asyncStreamReader = Substitute.For>(); var l = new List { @@ -492,8 +485,8 @@ public void TestCacheHit() // create an autoResetEvent which we will wait for in our test verification AutoResetEvent _autoResetEvent = new AutoResetEvent(false); - asyncStreamReader.Setup(a => a.MoveNext(It.IsAny())).ReturnsAsync(() => enumerator.MoveNext()); - asyncStreamReader.Setup(a => a.Current).Returns(() => + asyncStreamReader.MoveNext(Arg.Any()).Returns(enumerator.MoveNext()); + asyncStreamReader.Current.Returns(_ => { // set the autoResetEvent since this path should be the last one that's reached in the background task _autoResetEvent.Set(); @@ -501,7 +494,7 @@ public void TestCacheHit() }); var grpcEventStreamResp = new AsyncServerStreamingCall( - asyncStreamReader.Object, + asyncStreamReader, null, null, null, @@ -509,20 +502,19 @@ public void TestCacheHit() null ); - mockGrpcClient - .Setup(m => m.EventStream( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + mockGrpcClient.EventStream( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcEventStreamResp); - var mockCache = new Mock>(); - mockCache.Setup(c => c.TryGet(It.Is(s => s == "my-key"))).Returns( - () => new ResolutionDetails("my-key", true) - ); + var mockCache = Substitute.For>(); + mockCache.TryGet("my-key").Returns(new ResolutionDetails("my-key", true)); - var config = new FlagdConfig(); - config.CacheEnabled = true; - config.MaxEventStreamRetries = 1; - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, config, mockCache.Object); + var config = new FlagdConfig + { + CacheEnabled = true, + MaxEventStreamRetries = 1 + }; + var flagdProvider = new FlagdProvider(mockGrpcClient, config, mockCache); // resolve with default set to false to make sure we return what the grpc server gives us var val = flagdProvider.ResolveBooleanValue("my-key", false, null); @@ -530,8 +522,8 @@ public void TestCacheHit() // wait for the autoReset event to be fired before verifying the invocation of the mocked functions Assert.True(_autoResetEvent.WaitOne(10000)); - mockCache.VerifyAll(); - mockGrpcClient.VerifyAll(); + mockCache.Received(1).TryGet("my-key"); + mockGrpcClient.Received(1).EventStream(Arg.Any(), null, null, System.Threading.CancellationToken.None); } [Fact] @@ -548,13 +540,12 @@ public void TestCacheInvalidation() () => new Grpc.Core.Metadata(), () => { }); - var mockGrpcClient = new Mock(); - mockGrpcClient - .Setup(m => m.ResolveBooleanAsync( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) + var mockGrpcClient = Substitute.For(); + mockGrpcClient.ResolveBooleanAsync( + Arg.Any(), null, null, System.Threading.CancellationToken.None) .Returns(grpcResp); - var asyncStreamReader = new Mock>(); + var asyncStreamReader = Substitute.For>(); var configurationChangeData = new Struct(); var changedFlag = new Struct(); @@ -564,7 +555,7 @@ public void TestCacheInvalidation() var firstCall = true; - asyncStreamReader.Setup(a => a.MoveNext(It.IsAny())).ReturnsAsync(() => true); + asyncStreamReader.MoveNext(Arg.Any()).Returns(true); // as long as we did not send our first request to the provider, we will not send a configuration_change event // after the value of the flag has been retrieved the first time, we will send a configuration_change to test if the // item is deleted from the cache @@ -572,8 +563,8 @@ public void TestCacheInvalidation() // create an autoResetEvent which we will wait for in our test verification AutoResetEvent _autoResetEvent = new AutoResetEvent(false); - asyncStreamReader.Setup(a => a.Current).Returns( - () => + asyncStreamReader.Current.Returns( + _ => { if (firstCall) { @@ -591,7 +582,7 @@ public void TestCacheInvalidation() ); var grpcEventStreamResp = new AsyncServerStreamingCall( - asyncStreamReader.Object, + asyncStreamReader, null, null, null, @@ -599,18 +590,14 @@ public void TestCacheInvalidation() null ); - mockGrpcClient - .Setup(m => m.EventStream( - It.IsAny(), null, null, System.Threading.CancellationToken.None)) - .Returns(() => - { - return grpcEventStreamResp; - }); + mockGrpcClient.EventStream( + Arg.Any(), null, null, System.Threading.CancellationToken.None) + .Returns(grpcEventStreamResp); - var mockCache = new Mock>(); - mockCache.Setup(c => c.TryGet(It.Is(s => s == "my-key"))).Returns(() => null); - mockCache.Setup(c => c.Add(It.Is(s => s == "my-key"), It.IsAny())); - mockCache.Setup(c => c.Delete(It.Is(s => s == "my-key"))).Callback(() => + var mockCache = Substitute.For>(); + mockCache.TryGet(Arg.Is(s => s == "my-key")).Returns(null); + mockCache.Add(Arg.Is(s => s == "my-key"), Arg.Any()); + mockCache.When(x => x.Delete("my-key")).Do(_ => { // set the autoResetEvent since this path should be the last one that's reached in the background task _autoResetEvent.Set(); @@ -620,7 +607,7 @@ public void TestCacheInvalidation() var config = new FlagdConfig(); config.CacheEnabled = true; config.MaxEventStreamRetries = 1; - var flagdProvider = new FlagdProvider(mockGrpcClient.Object, config, mockCache.Object); + var flagdProvider = new FlagdProvider(mockGrpcClient, config, mockCache); // resolve with default set to false to make sure we return what the grpc server gives us var val = flagdProvider.ResolveBooleanValue("my-key", false, null); @@ -634,8 +621,10 @@ public void TestCacheInvalidation() Assert.True(_autoResetEvent.WaitOne(10000)); - mockCache.VerifyAll(); - mockGrpcClient.VerifyAll(); + mockCache.Received(2).TryGet("my-key"); + mockCache.Received(2).Add("my-key", Arg.Any()); + mockCache.Received().Delete("my-key"); + mockGrpcClient.Received(1).EventStream(Arg.Any(), null, null, System.Threading.CancellationToken.None); } } } diff --git a/test/OpenFeature.Contrib.Providers.GOFeatureFlag.Test/HttpClientMock.cs b/test/OpenFeature.Contrib.Providers.GOFeatureFlag.Test/HttpClientMock.cs deleted file mode 100644 index 6af6bbf2..00000000 --- a/test/OpenFeature.Contrib.Providers.GOFeatureFlag.Test/HttpClientMock.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Moq; -using Moq.Protected; - -namespace OpenFeature.Contrib.Providers.GOFeatureFlag.Test; - -public class HttpClientMock -{ - public static Mock GetResults(T response) - { - var mockResponse = new HttpResponseMessage - { - Content = new StringContent(JsonSerializer.Serialize(response)), - StatusCode = HttpStatusCode.OK - }; - - mockResponse.Content.Headers.ContentType = - new MediaTypeHeaderValue("application/json"); - var mockHandler = new Mock(); - mockHandler - .Protected() - .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(mockResponse); - return mockHandler; - } -} \ No newline at end of file