44import mock
55
66import grpc
7+ from grpc.experimental import aio
78import math
89import pytest
910
@@ -17,6 +18,7 @@ from {{ (api.naming.module_namespace + (api.naming.versioned_module_name,) + ser
1718from {{ (api.naming.module_namespace + (api.naming.versioned_module_name,) + service.meta.address.subpackage)|join(".") }}.services.{{ service.name|snake_case }} import transports
1819from google.api_core import client_options
1920from google.api_core import grpc_helpers
21+ from google.api_core import grpc_helpers_async
2022{% if service .has_lro -%}
2123from google.api_core import future
2224from google.api_core import operations_v1
@@ -213,6 +215,89 @@ def test_{{ method.name|snake_case }}(transport: str = 'grpc'):
213215 {% endfor %}
214216 {% endif %}
215217
218+
219+ @pytest.mark.asyncio
220+ async def test_{{ method.name|snake_case }}_async(transport: str = 'grpc_asyncio'):
221+ client = {{ service.async_client_name }}(
222+ credentials=credentials.AnonymousCredentials(),
223+ transport=transport,
224+ )
225+
226+ # Everything is optional in proto3 as far as the runtime is concerned,
227+ # and we are mocking out the actual API, so just send an empty request.
228+ request = {{ method.input.ident }}()
229+ {% if method .client_streaming %}
230+ requests = [request]
231+ {% endif %}
232+
233+ # Mock the actual call within the gRPC stub, and fake the request.
234+ with mock.patch.object(
235+ type(client._client._transport.{{ method.name|snake_case }}),
236+ '__call__') as call:
237+ # Designate an appropriate return value for the call.
238+ {% if method .void -%}
239+ call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None)
240+ {% elif method .lro -%}
241+ call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(
242+ operations_pb2.Operation(name='operations/spam')
243+ )
244+ {% elif not method .client_streaming and method .server_streaming -%}
245+ call.return_value = mock.Mock(aio.UnaryStreamCall, autospec=True)
246+ call.return_value.read = mock.AsyncMock(side_effect=[{{ method.output.ident }}()])
247+ {% elif method .client_streaming and method .server_streaming -%}
248+ call.return_value = mock.Mock(aio.StreamStreamCall, autospec=True)
249+ call.return_value.read = mock.AsyncMock(side_effect=[{{ method.output.ident }}()])
250+ {% else -%}
251+ call.return_value ={{' '}}
252+ {% - if not method .client_streaming and not method .server_streaming -%}
253+ grpc_helpers_async.FakeUnaryUnaryCall
254+ {% - else -%}
255+ grpc_helpers_async.FakeStreamUnaryCall
256+ {% - endif -%} ({{ method.output.ident }}(
257+ {% - for field in method .output .fields .values () | rejectattr ('message' ) %}
258+ {{ field.name }}={{ field.mock_value }},
259+ {% - endfor %}
260+ ))
261+ {% endif -%}
262+ {% if method .client_streaming and method .server_streaming %}
263+ response = await client.{{ method.name|snake_case }}(iter(requests))
264+ {% elif method .client_streaming and not method .server_streaming %}
265+ response = await (await client.{{ method.name|snake_case }}(iter(requests)))
266+ {% else %}
267+ response = await client.{{ method.name|snake_case }}(request)
268+ {% endif %}
269+
270+ # Establish that the underlying gRPC stub method was called.
271+ assert len(call.mock_calls)
272+ _, args, _ = call.mock_calls[0]
273+ {% if method .client_streaming %}
274+ assert next(args[0]) == request
275+ {% else %}
276+ assert args[0] == request
277+ {% endif %}
278+
279+ # Establish that the response is the type that we expect.
280+ {% if method .void -%}
281+ assert response is None
282+ {% elif method .lro -%}
283+ assert isinstance(response, future.Future)
284+ {% elif method .server_streaming -%}
285+ message = await response.read()
286+ assert isinstance(message, {{ method.output.ident }})
287+ {% else -%}
288+ assert isinstance(response, {{ method.client_output_async.ident }})
289+ {% for field in method .output .fields .values () | rejectattr ('message' ) -%}
290+ {% if field .field_pb .type in [1, 2] -%} {# Use approx eq for floats -#}
291+ assert math.isclose(response.{{ field.name }}, {{ field.mock_value }}, rel_tol=1e-6)
292+ {% elif field .field_pb .type == 8 -%} {# Use 'is' for bools #}
293+ assert response.{{ field.name }} is {{ field.mock_value }}
294+ {% else -%}
295+ assert response.{{ field.name }} == {{ field.mock_value }}
296+ {% endif -%}
297+ {% endfor %}
298+ {% endif %}
299+
300+
216301{% if method .field_headers %}
217302def test_{{ method.name|snake_case }}_field_headers():
218303 client = {{ service.client_name }}(
0 commit comments