This is an automated email from the ASF dual-hosted git repository. florianhockmann pushed a commit to branch TINKERPOP-2984-replace-moq in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit be1dea6776ac7152f4266d162fccfa9d88fd5505 Author: Florian Hockmann <[email protected]> AuthorDate: Wed Aug 16 14:59:38 2023 +0200 TINKERPOP-2984 Replace Moq with NSubstitute WIP Still missing are the logging tests. Looks like NSubstitute still lacks some functionality for this, but it should be supported soon: https://github.com/nsubstitute/NSubstitute/issues/634 --- .../Driver/ConnectionPoolTests.cs | 238 ++++++++++----------- .../Gremlin.Net.UnitTest/Driver/ConnectionTests.cs | 205 +++++++++--------- .../Driver/DriverRemoteConnectionTests.cs | 8 +- .../Gremlin.Net.UnitTest.csproj | 1 + .../Process/Remote/RemoteTransactionTests.cs | 6 +- .../Structure/IO/GraphSON/GraphSONReaderTests.cs | 8 +- .../Structure/IO/GraphSON/GraphSONWriterTests.cs | 24 ++- 7 files changed, 242 insertions(+), 248 deletions(-) diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionPoolTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionPoolTests.cs index 0fbc02aadb..078440118c 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionPoolTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionPoolTests.cs @@ -28,7 +28,9 @@ using System.Threading.Tasks; using Gremlin.Net.Driver; using Gremlin.Net.Driver.Exceptions; using Microsoft.Extensions.Logging.Abstractions; -using Moq; +using NSubstitute; +using NSubstitute.ExceptionExtensions; +using NSubstitute.Extensions; using Xunit; namespace Gremlin.Net.UnitTest.Driver @@ -41,24 +43,24 @@ namespace Gremlin.Net.UnitTest.Driver [InlineData(10)] public void ShouldEstablishConfiguredNrConnections(int poolSize) { - var mockedConnectionFactory = new Mock<IConnectionFactory>(); - var mockedConnection = new Mock<IConnection>(); - mockedConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockedConnection.Object); - var pool = CreateConnectionPool(mockedConnectionFactory.Object, poolSize); + var mockedConnectionFactory = Substitute.For<IConnectionFactory>(); + var mockedConnection = Substitute.For<IConnection>(); + mockedConnectionFactory.CreateConnection().Returns(mockedConnection); + var pool = CreateConnectionPool(mockedConnectionFactory, poolSize); Assert.Equal(poolSize, pool.NrConnections); - mockedConnectionFactory.Verify(m => m.CreateConnection(), Times.Exactly(poolSize)); - mockedConnection.Verify(m => m.ConnectAsync(It.IsAny<CancellationToken>()), Times.Exactly(poolSize)); + mockedConnectionFactory.Received(poolSize).CreateConnection(); + mockedConnection.Received(poolSize).ConnectAsync(Arg.Any<CancellationToken>()); } [Fact] public void GetAvailableConnectionShouldReturnFirstOpenConnection() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); var openConnectionToReturn = OpenConnection; - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()).Returns(ClosedConnection) - .Returns(ClosedConnection).Returns(openConnectionToReturn); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 3); + fakeConnectionFactory.CreateConnection().Returns(_ => ClosedConnection, _ => ClosedConnection, + _ => openConnectionToReturn); + var pool = CreateConnectionPool(fakeConnectionFactory, 3); var returnedConnection = pool.GetAvailableConnection(); @@ -68,9 +70,9 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void GetAvailableConnectionShouldThrowIfAllConnectionsAreClosed() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection().Returns(_ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory); Assert.Throws<ServerUnavailableException>(() => pool.GetAvailableConnection()); } @@ -78,11 +80,11 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void GetAvailableConnectionShouldEmptyPoolIfServerUnavailable() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()).Returns(ClosedConnection) - .Returns(ClosedConnection).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 3); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(CannotConnectConnection); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection() + .Returns(_ => ClosedConnection, _ => ClosedConnection, _ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 3); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => CannotConnectConnection); Assert.Throws<ServerUnavailableException>(() => pool.GetAvailableConnection()); @@ -92,15 +94,15 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void GetAvailableConnectionShouldEventuallyRefillPoolIfEmpty() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()).Returns(ClosedConnection) - .Returns(ClosedConnection).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 3); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(CannotConnectConnection); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection() + .Returns(_ => ClosedConnection, _ => ClosedConnection, _ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 3); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => CannotConnectConnection); Assert.Throws<ServerUnavailableException>(() => pool.GetAvailableConnection()); // Pool is now empty - Assert.Equal(0, pool.NrConnections); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(OpenConnection); + Assert.Equal(0, pool.NrConnections); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => OpenConnection); pool.GetAvailableConnection(); @@ -110,19 +112,17 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void GetAvailableConnectionsShouldEventuallyFillUpPoolIfNotFull() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()) - .Returns(ClosedConnection) - .Returns(ClosedConnection) - .Returns(OpenConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 3); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(CannotConnectConnection); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection() + .Returns(_ => ClosedConnection, _ => ClosedConnection, _ => OpenConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 3); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => CannotConnectConnection); pool.GetAvailableConnection(); pool.GetAvailableConnection(); // Pool is now just partially filled Assert.Equal(1, pool.NrConnections); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(OpenConnection); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => OpenConnection); pool.GetAvailableConnection(); AssertNrOpenConnections(pool, 3); @@ -131,11 +131,11 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void GetAvailableConnectionShouldReplaceClosedConnections() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()).Returns(ClosedConnection) - .Returns(ClosedConnection).Returns(OpenConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 3); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(OpenConnection); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection() + .Returns(_ => ClosedConnection, _ => ClosedConnection, _ => OpenConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 3); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => OpenConnection); var nrCreatedConnections = pool.NrConnections; pool.GetAvailableConnection(); @@ -158,11 +158,11 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public async Task ShouldNotCreateMoreConnectionsThanConfiguredForParallelRequests() { - var mockedConnectionFactory = new Mock<IConnectionFactory>(); - mockedConnectionFactory.SetupSequence(m => m.CreateConnection()).Returns(ClosedConnection) - .Returns(ClosedConnection).Returns(OpenConnection); - var pool = CreateConnectionPool(mockedConnectionFactory.Object, 3); - mockedConnectionFactory.Setup(m => m.CreateConnection()).Returns(OpenConnection); + var mockedConnectionFactory = Substitute.For<IConnectionFactory>(); + mockedConnectionFactory.CreateConnection() + .Returns(_ => ClosedConnection, _ => ClosedConnection, _ => OpenConnection); + var pool = CreateConnectionPool(mockedConnectionFactory, 3); + mockedConnectionFactory.Configure().CreateConnection().Returns(_ => OpenConnection); var nrCreatedConnections = pool.NrConnections; var getConnectionTasks = new List<Task<IConnection>>(); @@ -179,14 +179,14 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public async Task ShouldReplaceConnectionClosedDuringSubmit() { - var mockedConnectionFactory = new Mock<IConnectionFactory>(); - var fakedConnection = new Mock<IConnection>(); - fakedConnection.Setup(f => f.IsOpen).Returns(true); - mockedConnectionFactory.Setup(m => m.CreateConnection()).Returns(fakedConnection.Object); - var pool = CreateConnectionPool(mockedConnectionFactory.Object, 1); + var mockedConnectionFactory = Substitute.For<IConnectionFactory>(); + var fakedConnection = Substitute.For<IConnection>(); + fakedConnection.IsOpen.Returns(true); + mockedConnectionFactory.CreateConnection().Returns(fakedConnection); + var pool = CreateConnectionPool(mockedConnectionFactory, 1); var returnedConnection = pool.GetAvailableConnection(); - fakedConnection.Setup(f => f.IsOpen).Returns(false); - mockedConnectionFactory.Setup(m => m.CreateConnection()).Returns(OpenConnection); + fakedConnection.IsOpen.Returns(false); + mockedConnectionFactory.CreateConnection().Returns(_ => OpenConnection); await returnedConnection.SubmitAsync<bool>(null, CancellationToken.None); returnedConnection.Dispose(); @@ -198,10 +198,10 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void ShouldWaitForHostToBecomeAvailable() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 1); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(OpenConnection); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection().Returns(_ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 1); + fakeConnectionFactory.Configure().CreateConnection().Returns(_ => OpenConnection); var nrCreatedConnections = pool.NrConnections; var connection = pool.GetAvailableConnection(); @@ -216,13 +216,13 @@ namespace Gremlin.Net.UnitTest.Driver [InlineData(2)] public void ShouldPerformConfiguredNrReconnectionAttemptsForUnavailableServer(int nrAttempts) { - var mockedConnectionFactory = new Mock<IConnectionFactory>(); - mockedConnectionFactory.Setup(m => m.CreateConnection()).Returns(ClosedConnection); - var pool = CreateConnectionPool(mockedConnectionFactory.Object, 1, nrAttempts); + var mockedConnectionFactory = Substitute.For<IConnectionFactory>(); + mockedConnectionFactory.CreateConnection().Returns(_ => ClosedConnection); + var pool = CreateConnectionPool(mockedConnectionFactory, 1, nrAttempts); Assert.ThrowsAny<Exception>(() => pool.GetAvailableConnection()); - mockedConnectionFactory.Verify(m => m.CreateConnection(), Times.Exactly(nrAttempts + 2)); + mockedConnectionFactory.Received(nrAttempts + 2).CreateConnection(); // 2 additional calls are expected: 1 for the initial creation of the pool and 1 when the connection should // be returned and none is open for the first attempt (before any retries) } @@ -230,29 +230,29 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void ShouldThrowAfterWaitingTooLongForUnavailableServer() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 1); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection().Returns(_ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 1); Assert.Throws<ServerUnavailableException>(() => pool.GetAvailableConnection()); } - + [Fact] public async Task ShouldNotLeakConnectionsIfDisposeIsCalledWhilePoolIsPopulating() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 1); - var mockedConnectionToBeDisposed = new Mock<IConnection>(); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection().Returns(_ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 1); + var mockedConnectionToBeDisposed = Substitute.For<IConnection>(); var poolWasDisposedSignal = new SemaphoreSlim(0, 1); - mockedConnectionToBeDisposed.Setup(m => m.ConnectAsync(It.IsAny<CancellationToken>())) - .Returns((CancellationToken _) => poolWasDisposedSignal.WaitAsync(CancellationToken.None)); + mockedConnectionToBeDisposed.ConnectAsync(Arg.Any<CancellationToken>()) + .Returns(x => poolWasDisposedSignal.WaitAsync(CancellationToken.None)); var connectionWasSuccessfullyDisposed = new SemaphoreSlim(0, 1); - mockedConnectionToBeDisposed.Setup(m => m.Dispose()) - .Callback(() => connectionWasSuccessfullyDisposed.Release()); + mockedConnectionToBeDisposed.When(x => x.Dispose()) + .Do(_ => connectionWasSuccessfullyDisposed.Release()); // We don't use the `CancellationToken` here as the connection should also be disposed if it did not // react on the cancellation. This can happen if the task is cancelled just before `ConnectAsync` returns. - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockedConnectionToBeDisposed.Object); + fakeConnectionFactory.Configure().CreateConnection().Returns(mockedConnectionToBeDisposed); try { pool.GetAvailableConnection(); @@ -267,23 +267,23 @@ namespace Gremlin.Net.UnitTest.Driver await connectionWasSuccessfullyDisposed.WaitAsync(TimeSpan.FromSeconds(2)); Assert.Equal(0, pool.NrConnections); - mockedConnectionToBeDisposed.Verify(m => m.ConnectAsync(It.IsAny<CancellationToken>()), Times.Once); - mockedConnectionToBeDisposed.Verify(m => m.Dispose(), Times.Once); + await mockedConnectionToBeDisposed.Received(1).ConnectAsync(Arg.Any<CancellationToken>()); + mockedConnectionToBeDisposed.Received(1).Dispose(); } - + [Fact] public async Task DisposeShouldCancelConnectionEstablishment() { - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(ClosedConnection); - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 1, 0); - var mockedConnectionToBeDisposed = new Mock<IConnection>(); - mockedConnectionToBeDisposed.Setup(f => f.ConnectAsync(It.IsAny<CancellationToken>())) - .Returns((CancellationToken ct) => Task.Delay(-1, ct)); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection().Returns(_ => ClosedConnection); + var pool = CreateConnectionPool(fakeConnectionFactory, 1, 0); + var mockedConnectionToBeDisposed = Substitute.For<IConnection>(); + mockedConnectionToBeDisposed.ConnectAsync(Arg.Any<CancellationToken>()) + .Returns(x => Task.Delay(-1, (CancellationToken)x[0])); var connectionWasSuccessfullyDisposed = new SemaphoreSlim(0, 1); - mockedConnectionToBeDisposed.Setup(m => m.Dispose()) - .Callback(() => connectionWasSuccessfullyDisposed.Release()); - fakeConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockedConnectionToBeDisposed.Object); + mockedConnectionToBeDisposed.When(x => x.Dispose()) + .Do(_ => connectionWasSuccessfullyDisposed.Release()); + fakeConnectionFactory.Configure().CreateConnection().Returns(mockedConnectionToBeDisposed); try { pool.GetAvailableConnection(); @@ -294,11 +294,11 @@ namespace Gremlin.Net.UnitTest.Driver } pool.Dispose(); - + await connectionWasSuccessfullyDisposed.WaitAsync(TimeSpan.FromSeconds(2)); Assert.Equal(0, pool.NrConnections); - mockedConnectionToBeDisposed.Verify(m => m.ConnectAsync(It.IsAny<CancellationToken>())); - mockedConnectionToBeDisposed.Verify(m => m.Dispose(), Times.Once); + await mockedConnectionToBeDisposed.Received(1).ConnectAsync(Arg.Any<CancellationToken>()); + mockedConnectionToBeDisposed.Received(1).Dispose(); } [Fact] @@ -309,20 +309,19 @@ namespace Gremlin.Net.UnitTest.Driver // exception. // First create a pool with only closed connections that we can then let the pool replace: - var fakeConnectionFactory = new Mock<IConnectionFactory>(); - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()) - .Returns(ClosedConnection) // We need to do it like this as we use a dictionary of dead connections in - .Returns(ClosedConnection) // ConnectionPool and the three connections need to be different objects - .Returns(ClosedConnection);// for this to work. - var pool = CreateConnectionPool(fakeConnectionFactory.Object, 3, 0); + var fakeConnectionFactory = Substitute.For<IConnectionFactory>(); + fakeConnectionFactory.CreateConnection() + .Returns(_ => ClosedConnection, // We need to do it like this as we use a dictionary of dead connections in + _ => ClosedConnection, // ConnectionPool and the three connections need to be different objects + _ => ClosedConnection); // for this to work. + var pool = CreateConnectionPool(fakeConnectionFactory, 3, 0); var startEstablishingProblematicConnections = new SemaphoreSlim(0, 1); // Let the pool get one connection that is so slow to open that the pool will afterwards try to create two // more connections in parallel. - var fakedSlowToEstablishConnection = new Mock<IConnection>(); - fakedSlowToEstablishConnection.Setup(m => m.ConnectAsync(It.IsAny<CancellationToken>())) - .Returns(startEstablishingProblematicConnections.WaitAsync); - fakeConnectionFactory.Setup(m => m.CreateConnection()) - .Returns(fakedSlowToEstablishConnection.Object); + var fakedSlowToEstablishConnection = Substitute.For<IConnection>(); + fakedSlowToEstablishConnection.ConnectAsync(Arg.Any<CancellationToken>()) + .Returns(async _ => await startEstablishingProblematicConnections.WaitAsync()); + fakeConnectionFactory.Configure().CreateConnection().Returns(fakedSlowToEstablishConnection); // Trigger replacement of closed connections try { @@ -333,55 +332,48 @@ namespace Gremlin.Net.UnitTest.Driver // expected as the pool only contain closed connections at this point } - var fakedOpenConnection = FakedOpenConnection; - var fakedCannotConnectConnection = FakedCannotConnectConnection; - fakeConnectionFactory.SetupSequence(m => m.CreateConnection()) - .Returns(fakedOpenConnection.Object) - .Returns(fakedCannotConnectConnection.Object); + var fakedOpenConnection = OpenConnection; + var fakedCannotConnectConnection = CannotConnectConnection; + fakeConnectionFactory.Configure().CreateConnection() + .Returns(fakedOpenConnection, fakedCannotConnectConnection); // Let the slow to establish connection finish so the pool can try to establish the other two connections startEstablishingProblematicConnections.Release(); await Task.Delay(TimeSpan.FromMilliseconds(200)); // Verify that the pool tried to establish both connections and then also disposed both, even though one throw an exception - fakedOpenConnection.Verify(m => m.ConnectAsync(It.IsAny<CancellationToken>()), Times.Once()); - fakedOpenConnection.Verify(m => m.Dispose(), Times.Once); - fakedCannotConnectConnection.Verify(m => m.ConnectAsync(It.IsAny<CancellationToken>()), Times.Once); - fakedCannotConnectConnection.Verify(m => m.Dispose(), Times.Once); + await fakedOpenConnection.Received(1).ConnectAsync(Arg.Any<CancellationToken>()); + fakedOpenConnection.Received(1).Dispose(); + await fakedCannotConnectConnection.Received(1).ConnectAsync(Arg.Any<CancellationToken>()); + fakedCannotConnectConnection.Received(1).Dispose(); } - private static IConnection OpenConnection => FakedOpenConnection.Object; - - private static Mock<IConnection> FakedOpenConnection + private static IConnection OpenConnection { get { - var fakedConnection = new Mock<IConnection>(); - fakedConnection.Setup(f => f.IsOpen).Returns(true); + var fakedConnection = Substitute.For<IConnection>(); + fakedConnection.IsOpen.Returns(true); return fakedConnection; } } - - private static IConnection ClosedConnection => FakedClosedConnection.Object; - private static Mock<IConnection> FakedClosedConnection + private static IConnection ClosedConnection { get { - var fakedConnection = new Mock<IConnection>(); - fakedConnection.Setup(f => f.IsOpen).Returns(false); + var fakedConnection = Substitute.For<IConnection>(); + fakedConnection.IsOpen.Returns(false); return fakedConnection; } } - - private static IConnection CannotConnectConnection => FakedCannotConnectConnection.Object; - private static Mock<IConnection> FakedCannotConnectConnection + private static IConnection CannotConnectConnection { get { - var fakedConnection = new Mock<IConnection>(); - fakedConnection.Setup(f => f.IsOpen).Returns(false); - fakedConnection.Setup(f => f.ConnectAsync(It.IsAny<CancellationToken>())) + var fakedConnection = Substitute.For<IConnection>(); + fakedConnection.IsOpen.Returns(false); + fakedConnection.ConnectAsync(Arg.Any<CancellationToken>()) .Throws(new Exception("Cannot connect to server.")); return fakedConnection; } diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionTests.cs index 44c7105ba2..ef71d235d4 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/ConnectionTests.cs @@ -30,7 +30,9 @@ using Gremlin.Net.Driver; using Gremlin.Net.Driver.Exceptions; using Gremlin.Net.Driver.Messages; using Gremlin.Net.Structure.IO.GraphBinary; -using Moq; +using NSubstitute; +using NSubstitute.ExceptionExtensions; +using NSubstitute.Extensions; using Xunit; namespace Gremlin.Net.UnitTest.Driver @@ -40,56 +42,55 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public async Task ShouldHandleCloseMessageAfterConnectAsync() { - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .Setup(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>())) - .ReturnsAsync(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, WebSocketCloseStatus.MessageTooBig, "Message is too large")); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); - - Uri uri = new Uri("wss://localhost:8182"); - Connection connection = GetConnection(mockedClientWebSocket, uri: uri); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()).Returns( + new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, WebSocketCloseStatus.MessageTooBig, + "Message is too large")); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); + var uri = new Uri("wss://localhost:8182"); + var connection = GetConnection(mockedClientWebSocket, uri: uri); await connection.ConnectAsync(CancellationToken.None); Assert.False(connection.IsOpen); Assert.Equal(0, connection.NrRequestsInFlight); - mockedClientWebSocket.Verify(m => m.ConnectAsync(uri, It.IsAny<CancellationToken>()), Times.Once); - mockedClientWebSocket.Verify(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>()), Times.Once); - mockedClientWebSocket.Verify(m => m.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, It.IsAny<CancellationToken>()), Times.Once); + await mockedClientWebSocket.Received(1).ConnectAsync(uri, Arg.Any<CancellationToken>()); + await mockedClientWebSocket.Received(1) + .ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()); + await mockedClientWebSocket.Received(1).CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, + Arg.Any<CancellationToken>()); } [Fact] public async Task ShouldThrowIfClosedMessageReceivedWithValidPropertiesAsync() { - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); - WebSocketConnection webSocketConnection = new WebSocketConnection( - mockedClientWebSocket.Object, + var webSocketConnection = new WebSocketConnection( + mockedClientWebSocket, new WebSocketSettings()); // Test all known close statuses foreach (Enum closeStatus in Enum.GetValues(typeof(WebSocketCloseStatus))) { mockedClientWebSocket - .Setup(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>())) - .ReturnsAsync(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, (WebSocketCloseStatus)closeStatus, closeStatus.ToString())); + .ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()) + .Returns(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, (WebSocketCloseStatus)closeStatus, closeStatus.ToString())); await AssertExpectedConnectionClosedException((WebSocketCloseStatus?)closeStatus, closeStatus.ToString(), () => webSocketConnection.ReceiveMessageAsync()); } // Test null/empty close property values as well. mockedClientWebSocket - .Setup(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>())) - .ReturnsAsync(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, null, null)); + .ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()) + .Returns(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, null, null)); await AssertExpectedConnectionClosedException(null, null, () => webSocketConnection.ReceiveMessageAsync()); mockedClientWebSocket - .Setup(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>())) - .ReturnsAsync(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, null, String.Empty)); - await AssertExpectedConnectionClosedException(null, String.Empty, () => webSocketConnection.ReceiveMessageAsync()); + .ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()) + .Returns(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, null, string.Empty)); + await AssertExpectedConnectionClosedException(null, string.Empty, () => webSocketConnection.ReceiveMessageAsync()); } [Fact] @@ -98,35 +99,37 @@ namespace Gremlin.Net.UnitTest.Driver // This is to test that race bugs don't get introduced which would cause submitted requests to hang if the // connection is being closed/aborted or is not connected. In these cases, WebSocket.SendAsync should throw for the underlying // websocket is not open and the caller should be notified of that failure. - var mockedClientWebSocket = new Mock<IClientWebSocket>(); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); - Connection connection = GetConnection(mockedClientWebSocket); - RequestMessage request = RequestMessage.Build("gremlin").Create(); + var connection = GetConnection(mockedClientWebSocket); + var request = RequestMessage.Build("gremlin").Create(); // Simulate the SendAsync exception behavior if the underlying websocket is closed (see reference https://docs.microsoft.com/en-us/dotnet/api/system.net.websockets.clientwebsocket.sendasync?view=net-6.0) - mockedClientWebSocket.Setup(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), It.IsAny<CancellationToken>())) + mockedClientWebSocket + .SendAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<WebSocketMessageType>(), Arg.Any<bool>(), + Arg.Any<CancellationToken>()) .ThrowsAsync(new ObjectDisposedException(nameof(ClientWebSocket), "Socket closed")); // Test various closing/closed WebSocketStates with SubmitAsync. - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.Closed); + mockedClientWebSocket.State.Returns(WebSocketState.Closed); await Assert.ThrowsAsync<ObjectDisposedException>(() => connection.SubmitAsync<dynamic>(request, CancellationToken.None)); - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.CloseSent); + mockedClientWebSocket.State.Returns(WebSocketState.CloseSent); await Assert.ThrowsAsync<ObjectDisposedException>(() => connection.SubmitAsync<dynamic>(request, CancellationToken.None)); - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.CloseReceived); + mockedClientWebSocket.State.Returns(WebSocketState.CloseReceived); await Assert.ThrowsAsync<ObjectDisposedException>(() => connection.SubmitAsync<dynamic>(request, CancellationToken.None)); - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.Aborted); + mockedClientWebSocket.State.Returns(WebSocketState.Aborted); await Assert.ThrowsAsync<ObjectDisposedException>(() => connection.SubmitAsync<dynamic>(request, CancellationToken.None)); // Simulate SendAsync exception behavior if underlying websocket is not connected. - mockedClientWebSocket.Setup(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), It.IsAny<CancellationToken>())) - .ThrowsAsync(new InvalidOperationException("Socket not connected")); - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.Connecting); + mockedClientWebSocket + .SendAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<WebSocketMessageType>(), Arg.Any<bool>(), + Arg.Any<CancellationToken>()).ThrowsAsync(new InvalidOperationException("Socket not connected")); + mockedClientWebSocket.State.Returns(WebSocketState.Connecting); await Assert.ThrowsAsync<InvalidOperationException>(() => connection.SubmitAsync<dynamic>(request, CancellationToken.None)); } @@ -134,29 +137,27 @@ namespace Gremlin.Net.UnitTest.Driver public async Task ShouldHandleCloseMessageForInFlightRequestsAsync() { // Tests that in-flight requests will get notified if a connection close message is received. - Uri uri = new Uri("wss://localhost:8182"); - WebSocketReceiveResult closeResult = new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, WebSocketCloseStatus.EndpointUnavailable, "Server shutdown"); + var uri = new Uri("wss://localhost:8182"); + var closeResult = new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, WebSocketCloseStatus.EndpointUnavailable, "Server shutdown"); - var receiveSempahore = new SemaphoreSlim(0, 1); - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .Setup(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>())) - .Returns(async () => + var receiveSemaphore = new SemaphoreSlim(0, 1); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()) + .ReturnsForAnyArgs(async x => { - await receiveSempahore.WaitAsync(); - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.CloseReceived); + await receiveSemaphore.WaitAsync(); + mockedClientWebSocket.State.Returns(WebSocketState.CloseReceived); return closeResult; }); - mockedClientWebSocket.Setup(m => m.State).Returns(WebSocketState.Open); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + mockedClientWebSocket.State.Returns(WebSocketState.Open); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); var connection = GetConnection(mockedClientWebSocket, uri: uri); await connection.ConnectAsync(CancellationToken.None); // Create two in-flight requests that will block on waiting for a response. - RequestMessage requestMsg1 = RequestMessage.Build("gremlin").Create(); - RequestMessage requestMsg2 = RequestMessage.Build("gremlin").Create(); + var requestMsg1 = RequestMessage.Build("gremlin").Create(); + var requestMsg2 = RequestMessage.Build("gremlin").Create(); Task request1 = connection.SubmitAsync<dynamic>(requestMsg1, CancellationToken.None); Task request2 = connection.SubmitAsync<dynamic>(requestMsg2, CancellationToken.None); @@ -164,7 +165,7 @@ namespace Gremlin.Net.UnitTest.Driver Assert.Equal(2, connection.NrRequestsInFlight); // Release the connection close message. - receiveSempahore.Release(); + receiveSemaphore.Release(); // Assert that both requests get notified with the closed exception. await AssertExpectedConnectionClosedException(closeResult.CloseStatus, closeResult.CloseStatusDescription, () => request1); @@ -179,17 +180,18 @@ namespace Gremlin.Net.UnitTest.Driver Assert.False(connection.IsOpen); Assert.Equal(0, connection.NrRequestsInFlight); - mockedClientWebSocket.Verify(m => m.ConnectAsync(uri, It.IsAny<CancellationToken>()), Times.Once); - mockedClientWebSocket.Verify(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>()), Times.Once); - mockedClientWebSocket.Verify(m => m.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, It.IsAny<CancellationToken>()), Times.Once); + await mockedClientWebSocket.Received(1).ConnectAsync(uri, Arg.Any<CancellationToken>()); + await mockedClientWebSocket.Received(1) + .ReceiveAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<CancellationToken>()); + await mockedClientWebSocket.Received(1).CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, + Arg.Any<CancellationToken>()); } [Fact] public async Task ShouldProperlyHandleCancellationForSubmitAsync() { - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); var connection = GetConnection(mockedClientWebSocket); var cts = new CancellationTokenSource(); @@ -199,21 +201,18 @@ namespace Gremlin.Net.UnitTest.Driver await Assert.ThrowsAsync<TaskCanceledException>(async () => await task); Assert.True(task.IsCanceled); - mockedClientWebSocket.Verify(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), - It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), cts.Token), Times.Once); - mockedClientWebSocket.Verify( - m => m.CloseAsync(It.IsAny<WebSocketCloseStatus>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), - Times.Never); - mockedClientWebSocket.Verify( - m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), cts.Token), Times.Never); + await mockedClientWebSocket.Received(1).SendAsync(Arg.Any<ArraySegment<byte>>(), + Arg.Any<WebSocketMessageType>(), Arg.Any<bool>(), cts.Token); + await mockedClientWebSocket.DidNotReceive().CloseAsync(Arg.Any<WebSocketCloseStatus>(), Arg.Any<string>(), + Arg.Any<CancellationToken>()); + await mockedClientWebSocket.DidNotReceive().ReceiveAsync(Arg.Any<ArraySegment<byte>>(), cts.Token); } [Fact] public async Task ShouldProperlyHandleCancellationForSubmitAsyncIfAlreadyCancelled() { - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); var connection = GetConnection(mockedClientWebSocket); var token = new CancellationToken(canceled: true); @@ -222,25 +221,21 @@ namespace Gremlin.Net.UnitTest.Driver await Assert.ThrowsAsync<TaskCanceledException>(async () => await task); Assert.True(task.IsCanceled); - mockedClientWebSocket.Verify( - m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), - It.IsAny<CancellationToken>()), Times.Never); - mockedClientWebSocket.Verify( - m => m.CloseAsync(It.IsAny<WebSocketCloseStatus>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), - Times.Never); - mockedClientWebSocket.Verify( - m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), token), Times.Never); + await mockedClientWebSocket.DidNotReceive().SendAsync(Arg.Any<ArraySegment<byte>>(), + Arg.Any<WebSocketMessageType>(), Arg.Any<bool>(), Arg.Any<CancellationToken>()); + await mockedClientWebSocket.DidNotReceive().CloseAsync(Arg.Any<WebSocketCloseStatus>(), Arg.Any<string>(), + Arg.Any<CancellationToken>()); + await mockedClientWebSocket.DidNotReceive().ReceiveAsync(Arg.Any<ArraySegment<byte>>(), token); } [Fact] public async Task ShouldContinueSubmittingOtherMessagesIfOneIsCancelled() { - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); var tcs = new TaskCompletionSource(); - mockedClientWebSocket.Setup(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), - It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), It.IsAny<CancellationToken>())).Returns(tcs.Task); + mockedClientWebSocket.SendAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<WebSocketMessageType>(), + Arg.Any<bool>(), Arg.Any<CancellationToken>()).Returns(tcs.Task); var connection = GetConnection(mockedClientWebSocket); var cts = new CancellationTokenSource(); @@ -256,27 +251,25 @@ namespace Gremlin.Net.UnitTest.Driver await Assert.ThrowsAsync<TaskCanceledException>(async () => await taskToCancel); Assert.True(taskToCancel.IsCanceled); await Task.Delay(TimeSpan.FromMilliseconds(200)); // wait a bit to let the messages being sent - mockedClientWebSocket.Verify(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), - It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()), Times.Exactly(3)); + await mockedClientWebSocket.Received(3).SendAsync(Arg.Any<ArraySegment<byte>>(), + Arg.Any<WebSocketMessageType>(), Arg.Any<bool>(), Arg.Any<CancellationToken>()); } [Fact] public async Task ShouldContinueSubmittingOtherMessagesIfOneIsAlreadyCancelled() { - var mockedClientWebSocket = new Mock<IClientWebSocket>(); - mockedClientWebSocket - .SetupGet(m => m.Options).Returns(new ClientWebSocket().Options); + var mockedClientWebSocket = Substitute.For<IClientWebSocket>(); + mockedClientWebSocket.Options.Returns(new ClientWebSocket().Options); var cancelledToken = new CancellationToken(canceled: true); - mockedClientWebSocket - .Setup(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<WebSocketMessageType>(), - It.IsAny<bool>(), cancelledToken)) - .ThrowsAsync(new TaskCanceledException(null, null, cancelledToken)); + mockedClientWebSocket.SendAsync(Arg.Any<ArraySegment<byte>>(), Arg.Any<WebSocketMessageType>(), + Arg.Any<bool>(), cancelledToken) + .Throws(new TaskCanceledException(null, null, cancelledToken)); var messageToSend = RequestMessage.Build(string.Empty).Create(); - var fakeMessageSerializer = new Mock<IMessageSerializer>(); + var fakeMessageSerializer = Substitute.For<IMessageSerializer>(); var bytesToSend = new byte[] { 1, 2, 3 }; - fakeMessageSerializer.Setup(f => f.SerializeMessageAsync(messageToSend, It.IsAny<CancellationToken>())) - .ReturnsAsync(bytesToSend); - var connection = GetConnection(mockedClientWebSocket, fakeMessageSerializer.Object); + fakeMessageSerializer.SerializeMessageAsync(messageToSend, Arg.Any<CancellationToken>()) + .Returns(bytesToSend); + var connection = GetConnection(mockedClientWebSocket, fakeMessageSerializer); var taskToCancel = connection.SubmitAsync<object>(RequestMessage.Build(string.Empty).Create(), cancelledToken); @@ -284,26 +277,26 @@ namespace Gremlin.Net.UnitTest.Driver await Assert.ThrowsAsync<TaskCanceledException>(async () => await taskToCancel); Assert.True(taskToCancel.IsCanceled); - mockedClientWebSocket.Verify(m => m.SendAsync(bytesToSend, - It.IsAny<WebSocketMessageType>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()), Times.Exactly(1)); + await mockedClientWebSocket.Received(1).SendAsync(bytesToSend, Arg.Any<WebSocketMessageType>(), + Arg.Any<bool>(), Arg.Any<CancellationToken>()); } [Fact] public async Task ShouldNotProcessReceivedMessageForCancelledRequest() { - var fakeMessageSerializer = new Mock<IMessageSerializer>(); + var fakeMessageSerializer = Substitute.For<IMessageSerializer>(); var receivedBytes = new byte[] { 1, 2, 3 }; var messageToCancel = RequestMessage.Build(string.Empty).Create(); var receivedMessage = new ResponseMessage<List<object>> { RequestId = messageToCancel.RequestId, Status = new ResponseStatus { Code = ResponseStatusCode.Success } }; - fakeMessageSerializer.Setup(f => f.DeserializeMessageAsync(receivedBytes, It.IsAny<CancellationToken>())) - .ReturnsAsync(receivedMessage); - var fakeWebSocketConnection = new Mock<IWebSocketConnection>(); + fakeMessageSerializer.DeserializeMessageAsync(receivedBytes, Arg.Any<CancellationToken>()) + .Returns(receivedMessage); + var fakeWebSocketConnection = Substitute.For<IWebSocketConnection>(); var receiveTaskCompletionSource = new TaskCompletionSource<byte[]>(); - fakeWebSocketConnection.Setup(m => m.ReceiveMessageAsync()).Returns(receiveTaskCompletionSource.Task); - var connection = GetConnection(fakeWebSocketConnection.Object, fakeMessageSerializer.Object); + fakeWebSocketConnection.ReceiveMessageAsync().Returns(receiveTaskCompletionSource.Task); + var connection = GetConnection(fakeWebSocketConnection, fakeMessageSerializer); await connection.ConnectAsync(CancellationToken.None); var cts = new CancellationTokenSource(); @@ -315,11 +308,11 @@ namespace Gremlin.Net.UnitTest.Driver Assert.Equal(0, connection.NrRequestsInFlight); } - private static Connection GetConnection(IMock<IClientWebSocket> mockedClientWebSocket, + private static Connection GetConnection(IClientWebSocket clientWebSocket, IMessageSerializer messageSerializer = null, Uri uri = null) { - return GetConnection(new WebSocketConnection(mockedClientWebSocket.Object, new WebSocketSettings()), - messageSerializer, uri); + return GetConnection(new WebSocketConnection(clientWebSocket, new WebSocketSettings()), messageSerializer, + uri); } private static Connection GetConnection(IWebSocketConnection webSocketConnection, diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs index 7ed9c96fef..de09081f6b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs @@ -24,7 +24,7 @@ using System; using Gremlin.Net.Driver; using Gremlin.Net.Driver.Remote; -using Moq; +using NSubstitute; using Xunit; namespace Gremlin.Net.UnitTest.Driver @@ -34,12 +34,12 @@ namespace Gremlin.Net.UnitTest.Driver [Fact] public void ShouldDisposeProvidedGremlinClientOnDispose() { - var gremlinClientMock = new Mock<IGremlinClient>(); - var driverRemoteConnection = new DriverRemoteConnection(gremlinClientMock.Object); + var gremlinClient = Substitute.For<IGremlinClient>(); + var driverRemoteConnection = new DriverRemoteConnection(gremlinClient); driverRemoteConnection.Dispose(); - gremlinClientMock.Verify(m => m.Dispose()); + gremlinClient.Received().Dispose(); } [Fact] diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj index 9736882f46..52a7000d9e 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj @@ -14,6 +14,7 @@ <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" /> <PackageReference Include="Moq" Version="4.18.4" /> + <PackageReference Include="NSubstitute" Version="5.0.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" /> <PackageReference Include="xunit" Version="2.4.2" /> </ItemGroup> diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Remote/RemoteTransactionTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Remote/RemoteTransactionTests.cs index 284566c3f5..45ec88bc28 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Remote/RemoteTransactionTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Remote/RemoteTransactionTests.cs @@ -25,7 +25,7 @@ using System; using Gremlin.Net.Driver; using Gremlin.Net.Driver.Remote; using Gremlin.Net.Process.Traversal; -using Moq; +using NSubstitute; using Xunit; namespace Gremlin.Net.UnitTest.Process.Remote @@ -36,7 +36,7 @@ namespace Gremlin.Net.UnitTest.Process.Remote public void ShouldNotAllowBeginMoreThanOnce() { var g = AnonymousTraversalSource.Traversal() - .WithRemote(new DriverRemoteConnection(Mock.Of<IGremlinClient>())); + .WithRemote(new DriverRemoteConnection(Substitute.For<IGremlinClient>())); var tx = g.Tx(); tx.Begin(); @@ -47,7 +47,7 @@ namespace Gremlin.Net.UnitTest.Process.Remote public void ShouldNotSupportChildTransactions() { var g = AnonymousTraversalSource.Traversal() - .WithRemote(new DriverRemoteConnection(Mock.Of<IGremlinClient>())); + .WithRemote(new DriverRemoteConnection(Substitute.For<IGremlinClient>())); var tx = g.Tx(); var gtx = tx.Begin(); diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs index 5bc232beed..b42f973bd4 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs @@ -28,7 +28,7 @@ using System.Text.Json; using Gremlin.Net.Process.Traversal; using Gremlin.Net.Structure; using Gremlin.Net.Structure.IO.GraphSON; -using Moq; +using NSubstitute; using Xunit; namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON @@ -80,11 +80,11 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON [Fact] public void ShouldDeserializeWithCustomDeserializerForCommonType() { - var customSerializerMock = new Mock<IGraphSONDeserializer>(); + var customSerializerMock = Substitute.For<IGraphSONDeserializer>(); const string overrideTypeString = "g:Int64"; var customSerializerByType = new Dictionary<string, IGraphSONDeserializer> { - {overrideTypeString, customSerializerMock.Object} + {overrideTypeString, customSerializerMock} }; var reader = new GraphSON2Reader(customSerializerByType); @@ -92,7 +92,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON JsonSerializer.Deserialize<JsonElement>($"{{\"@type\":\"{overrideTypeString}\",\"@value\":12}}"); var deserializedValue = reader.ToObject(jsonElement); - customSerializerMock.Verify(m => m.Objectify(It.IsAny<JsonElement>(), It.IsAny<GraphSONReader>())); + customSerializerMock.Received(1).Objectify(Arg.Any<JsonElement>(), Arg.Any<GraphSONReader>()); } [Theory, MemberData(nameof(Versions))] diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs index ce593f74ba..9fa612c3db 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs @@ -28,7 +28,6 @@ using Gremlin.Net.Process.Traversal; using Gremlin.Net.Process.Traversal.Strategy.Decoration; using Gremlin.Net.Structure; using Gremlin.Net.Structure.IO.GraphSON; -using Moq; using Xunit; namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON @@ -202,18 +201,27 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON [Fact] public void ShouldSerializeWithCustomSerializerForCommonType() { - var customSerializerMock = new Mock<IGraphSONSerializer>(); - customSerializerMock.Setup(m => m.Dictify(It.IsAny<int>(), It.IsAny<GraphSONWriter>())) - .Returns(new Dictionary<string, dynamic>()); + var customSerializer = new CustomDummySerializer(); var customSerializerByType = new Dictionary<Type, IGraphSONSerializer> { - {typeof(int), customSerializerMock.Object} + {typeof(int), customSerializer} }; var writer = new GraphSON2Writer(customSerializerByType); - + writer.WriteObject(12); - - customSerializerMock.Verify(m => m.Dictify(It.Is<int>(v => v == 12), It.IsAny<GraphSONWriter>())); + + Assert.Equal(12, customSerializer.DictifiedLast); + } + + private class CustomDummySerializer : IGraphSONSerializer + { + public dynamic DictifiedLast { get; private set; } + + public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer) + { + DictifiedLast = objectData; + return new Dictionary<string, dynamic>(); + } } [Theory, MemberData(nameof(Versions))]
