繁体   English   中英

模拟 gRPC 响应 Stream 用于单元测试 - C#

[英]Mock gRPC Response Stream for unit testing - C#

我有一个 function 调用 gRPC 端点,将对象转换为 POCO 对象并将它们作为列表返回。

public class ActionPlanConnectionsService : IConnectionService
    {
            #region Fields
    
            /// <summary>
            /// Grpc client
            /// </summary>
            private readonly ConnectionDb.ConnectionDbClient _client;
            #endregion
    
            public ActionPlanConnectionsService(ConnectionDb.ConnectionDbClient channel)
            {
                _client = channel;
            }
    
            public async Task<IEnumerable<Connection>> Get(int actionPlanId, int implementation)
            {
               List<Connection> diagramConnections = new List<Connection>();
               GetConnectionsByIdAndImplementationMessage message = new GetConnectionsByIdAndImplementationMessage
               {
                   ActionPlanId = actionPlanId,
                   Implementation = implementation
               };
    
               using var call = _client.GetAllConnections(message);
               await foreach (ConnectionServiceModel connection in call.ResponseStream.ReadAllAsync())
               {
                   // Never enters here as ResponseStream has no elements when unit testing!!
                   diagramConnections.Add(new Connection(
                       connection.FromActionPlanStepId, connection.ToActionPlanStepId, connection.ActionPlanId,
                       connection.Qualifier, connection.Implementation, connection.Path));
               }
    
               return diagramConnections;
           }
   }

我一直在为此 function 开发单元测试,但返回的列表始终计数为零。 这是因为 ResponseStream 内部没有元素。

如何模拟 ResponseStream?

到目前为止我的单元测试:

[Test]
        public async Task GetConnectionsTest()
        {
            // Arrange
            Mock<ConnectionDb.ConnectionDbClient> mockClient = new Mock<ConnectionDb.ConnectionDbClient>();
            Mock<IAsyncStreamReader<ConnectionServiceModel>> mockResponseStream
                = new Mock<IAsyncStreamReader<ConnectionServiceModel>>();

            List<ConnectionServiceModel> connectionServiceModels =
                new List<ConnectionServiceModel>
                {
                    new ConnectionServiceModel
                    {
                        ActionPlanId = 1,
                        FromActionPlanStepId = 1,
                        ToActionPlanStepId = 1,
                        Implementation = 0,
                        Qualifier = 1,
                        Path = " 1;2;3;4;5;6;7;8;9;10;11;12;13;14"
                    }
                };

            var fakeCall = TestCalls.AsyncServerStreamingCall
                (mockResponseStream.Object,
                Task.FromResult(new Metadata()), () => Status.DefaultSuccess,
                () => new Metadata(), () => { });

            mockClient.Setup(m => m.GetAllConnections(
                It.IsAny<GetConnectionsByIdAndImplementationMessage>(),
                null, null, CancellationToken.None)).Returns(fakeCall);

            // Act
            ActionPlanConnectionsService service = new ActionPlanConnectionsService(mockClient.Object);
            IEnumerable<Connection> connections = await service.Get(1, 1);

            // Assert
            
            // CONNECTIONS WILL ALWAYS HAVE 0 Elements as the response isn't setup for it.
        }
    }

扩展@Jan Tattermusch 推荐的内容,您可能只想实现IAsyncStreamReader而不是尝试模拟它。 这是一个基于枚举器的简单实现。

internal class MyAsyncStreamReader<T> : IAsyncStreamReader<T>
{
    private readonly IEnumerator<T> enumerator;

    public MyAsyncStreamReader(IEnumerable<T> results)
    {
        enumerator = results.GetEnumerator();
    }

    public T Current => enumerator.Current;

    public Task<bool> MoveNext(CancellationToken cancellationToken) =>
        Task.Run(() => enumerator.MoveNext());
}

然后这样的事情应该工作:

        [Test]
        public async Task GetConnectionsTest()
        {
            // Arrange
            Mock<ConnectionDb.ConnectionDbClient> mockClient = new Mock<ConnectionDb.ConnectionDbClient>();

            List<ConnectionServiceModel> connectionServiceModels =
                new List<ConnectionServiceModel>
                {
                    new ConnectionServiceModel
                    {
                        ActionPlanId = 1,
                        FromActionPlanStepId = 1,
                        ToActionPlanStepId = 1,
                        Implementation = 0,
                        Qualifier = 1,
                        Path = " 1;2;3;4;5;6;7;8;9;10;11;12;13;14"
                    }
                };

            // Create your async stream reader
            var reader = new MyAsyncStreamReader<ConnectionServiceModel>(connectionServiceModels);

            var fakeCall = TestCalls.AsyncServerStreamingCall(
                reader, // Pass the stream reader into the gRPC call
                Task.FromResult(new Metadata()),
                () => Status.DefaultSuccess,
                () => new Metadata(),
                () => { });

            mockClient.Setup(m => m.GetAllConnections(
                It.IsAny<GetConnectionsByIdAndImplementationMessage>(),
                null, null, CancellationToken.None)).Returns(fakeCall);

            // Act
            ActionPlanConnectionsService service = new ActionPlanConnectionsService(mockClient.Object);
            IEnumerable<Connection> connections = await service.Get(1, 1);

            // Assert
            Assert.NotEmpty(connections); // Should pass
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM