[C#] Mocking server side streaming calls (ClientStream, ServerStream, Bidi)

59 views
Skip to first unread message

Joseph Vaughan

unread,
May 7, 2019, 4:57:34 AM5/7/19
to grpc.io
Hi,

I'm interested in unit testing with my service implementations, however I'm struggling to build suitable calls for the streaming situations. I'm fine testing them in "integration test" scenarios, will a full client/server setup (in proc), but would like to unit test them also.

Does anyone have any good solutions for substituting in the IServerStreamWriter, IClientStreamWriter, IAsyncStreamReader types, either under a mock framework or with test stubs?

Thanks,
Joe.

Christopher Warrington - MSFT

unread,
May 7, 2019, 5:35:52 PM5/7/19
to grpc.io
On Tuesday, May 7, 2019 at 1:57:34 AM UTC-7, Joseph Vaughan wrote:

> Does anyone have any good solutions for substituting in the
> IServerStreamWriter, IClientStreamWriter, IAsyncStreamReader types, either
> under a mock framework or with test stubs?

In my team's code base, we've divorced the business logic from the gRPC
handler implementation by using DataFlow [1] blocks. The business logic
doesn't even contain a reference to the gRPC assemblies at all. It does use
Proto messages. This makes the business logic easily unit testable.

We have small adapters from the gRPC interfaces to Dataflow blocks. The
service handlers use these adapters to bridge from IServerStreamWriter &
friends to the business logic's input/output types. These adapters get
tested in our server integration tests.

We have four different projects of interest here:

* core (class library): business logic
* core-tests (unit tests): tests for code in core
* service (executable): reads config, starts gRPC service, gRPC to business
  logic adapter (service handlers), Dataflow blocks adapter
* service-tests (integration tests): stands up full service using single-box
  config and exercises it

[1]: https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library

--
Christopher Warrington
Microsoft Corp.

Joseph Vaughan

unread,
May 9, 2019, 6:29:43 AM5/9/19
to grpc.io

Hi Christopher,

 

Thank you for your response, I had a feeling that this is the way that it should be approached. In my case the RPC is fairly straight forward, but I’d still like it to be testable, so perhaps using DataFlow blocks as you have is suitable. I’ll look into it thanks.

Jan Tattermusch

unread,
May 15, 2019, 8:54:50 AM5/15/19
to grpc.io
It shouldn't be hard to implement your own test doubles for IServerStreamWriterIClientStreamWriterIAsyncStreamReader 
the functionality of those interfaces is pretty trivial, so it shouldn't be much of an overhead writing those.

If you come up with something that you believe that can be reused by others, you can consider contributing to tho Grpc.Core.Testing package - https://github.com/grpc/grpc/tree/master/src/csharp/Grpc.Core.Testing (the package doesn't have much right now, but it's been meant to provide tools/test doubles to simplify unit testings).

Joseph Vaughan

unread,
May 15, 2019, 9:26:48 AM5/15/19
to grpc.io
This is the simple solution I came up with for now, I'll see if I can find some time to get a PR into the Grpc.Core.Testing package with a better API and doubles for the other interfaces. In the meanwhile perhaps this will help someone :-)

class MockClientRequestStream<T> : IAsyncStreamReader<T>
{
   
private readonly IEnumerator<T> _enumerator;

   
public MockClientRequestStream(IEnumerable<T> data)
   
{
        _enumerator
= data.GetEnumerator();
   
}

   
public void Dispose()
   
{
        _enumerator
.Dispose();
   
}

   
public Task<bool> MoveNext(CancellationToken cancellationToken)
   
{
       
return Task.FromResult(_enumerator.MoveNext());
   
}

   
public T Current => _enumerator.Current;
}


Reply all
Reply to author
Forward
0 new messages