All Projects → kataev → Pytest Grpc

kataev / Pytest Grpc

Allow test gRPC with pytest

Programming Languages

python
139335 projects - #7 most used programming language

Labels

Projects that are alternatives of or similar to Pytest Grpc

Schemathesis
A modern API testing tool for web applications built with Open API and GraphQL specifications.
Stars: ✭ 768 (+1119.05%)
Mutual labels:  pytest
Opensourcetest
OpenSourceTest由自动化测试-夜行者社区维护,提供的是更多地灵活性和可配置性
Stars: ✭ 37 (-41.27%)
Mutual labels:  pytest
Python web framework
这是一个关于python的WebUI自动化测试的项目,之前用的是unittest测试框架,现在改成pytest测试框架,Python+PageObject+Pytest
Stars: ✭ 49 (-22.22%)
Mutual labels:  pytest
Pytest Responsemock
Simplified requests calls mocking for pytest
Stars: ✭ 24 (-61.9%)
Mutual labels:  pytest
Jest Pytest
A Jest and Pytest integration made in heaven 💖
Stars: ✭ 28 (-55.56%)
Mutual labels:  pytest
Pytest Idapro
A pytest module for The Interactive Disassembler and IDAPython; Record and Replay IDAPython API, execute inside IDA or use mockups of IDAPython API.
Stars: ✭ 44 (-30.16%)
Mutual labels:  pytest
Pytest Benchmark
py.test fixture for benchmarking code
Stars: ✭ 730 (+1058.73%)
Mutual labels:  pytest
Pyautotest
Stars: ✭ 61 (-3.17%)
Mutual labels:  pytest
Pytest Cov
Coverage plugin for pytest.
Stars: ✭ 983 (+1460.32%)
Mutual labels:  pytest
Pytest Mypy Plugins
pytest plugin for testing mypy types, stubs, and plugins
Stars: ✭ 47 (-25.4%)
Mutual labels:  pytest
Pytest Requests
HTTP(S) testing with pytest and requests.
Stars: ✭ 24 (-61.9%)
Mutual labels:  pytest
Pytest Django
A Django plugin for pytest.
Stars: ✭ 872 (+1284.13%)
Mutual labels:  pytest
Pytest Pudb
Pytest PuDB debugger integration
Stars: ✭ 45 (-28.57%)
Mutual labels:  pytest
Pytest Ui
Text User Interface for running python tests
Stars: ✭ 23 (-63.49%)
Mutual labels:  pytest
Pytest Django Queries
Generate performance reports from your django database performance tests.
Stars: ✭ 54 (-14.29%)
Mutual labels:  pytest
Tavern
A command-line tool and Python library and Pytest plugin for automated testing of RESTful APIs, with a simple, concise and flexible YAML-based syntax
Stars: ✭ 760 (+1106.35%)
Mutual labels:  pytest
Pytest Mock
Thin-wrapper around the mock package for easier use with pytest
Stars: ✭ 1,020 (+1519.05%)
Mutual labels:  pytest
Integration tests
ManageIQ integration tests
Stars: ✭ 63 (+0%)
Mutual labels:  pytest
Dicomweb Client
Python client for DICOMweb RESTful services
Stars: ✭ 60 (-4.76%)
Mutual labels:  pytest
Pytest Mimesis
Mimesis integration with the pytest test runner. This plugin provider useful fixtures based on providers from Mimesis.
Stars: ✭ 46 (-26.98%)
Mutual labels:  pytest

pytest-grpc

Write test for gRPC with pytest.

Example

See example dir and/or read 'usage'.

Usage

For example you have some proto file with rpc declaration.

syntax = "proto3";

package test.v1;


service EchoService {
    rpc handler(EchoRequest) returns (EchoResponse) {
    }
}


message EchoRequest {
    string name = 1;
}

message EchoResponse {
    string name = 1;
}

After compile it with grpcio-tools, you get *_pb2.py and *_pb2_grpc.py files, now you can write your service.

from stub.test_pb2 import EchoRequest, EchoResponse
from stub.test_pb2_grpc import EchoServiceServicer


class Servicer(EchoServiceServicer):
    def handler(self, request: EchoRequest, context) -> EchoResponse:
        return EchoResponse(name=f'test-{request.name}')

    def error_handler(self, request: EchoRequest, context) -> EchoResponse:
        raise RuntimeError('Some error')

Point pytest with your stubs and service:

import pytest

from stub.test_pb2 import EchoRequest


@pytest.fixture(scope='module')
def grpc_add_to_server():
    from stub.test_pb2_grpc import add_EchoServiceServicer_to_server

    return add_EchoServiceServicer_to_server


@pytest.fixture(scope='module')
def grpc_servicer():
    from servicer import Servicer

    return Servicer()


@pytest.fixture(scope='module')
def grpc_stub_cls(grpc_channel):
    from stub.test_pb2_grpc import EchoServiceStub

    return EchoServiceStub

Write little test:

def test_some(grpc_stub):
    request = EchoRequest()
    response = grpc_stub.handler(request)

    assert response.name == f'test-{request.name}'

def test_example(grpc_stub):
    request = EchoRequest()
    response = grpc_stub.error_handler(request)

    assert response.name == f'test-{request.name}'

Testing secure server

from pathlib import Path
import pytest
import grpc

@pytest.fixture(scope='module')
def grpc_add_to_server():
    from stub.test_pb2_grpc import add_EchoServiceServicer_to_server

    return add_EchoServiceServicer_to_server


@pytest.fixture(scope='module')
def grpc_servicer():
    from servicer import Servicer

    return Servicer()


@pytest.fixture(scope='module')
def grpc_stub_cls(grpc_channel):
    from stub.test_pb2_grpc import EchoServiceStub

    return EchoServiceStub


@pytest.fixture(scope='session')
def my_ssl_key_path():
    return Path('/path/to/key.pem')


@pytest.fixture(scope='session')
def my_ssl_cert_path():
    return Path('/path/to/cert.pem')


@pytest.fixture(scope='module')
def grpc_server(_grpc_server, grpc_addr, my_ssl_key_path, my_ssl_cert_path):
    """
    Overwrites default `grpc_server` fixture with ssl credentials
    """
    credentials = grpc.ssl_server_credentials([
        (my_ssl_key_path.read_bytes(),
         my_ssl_cert_path.read_bytes())
    ])

    _grpc_server.add_secure_port(grpc_addr, server_credentials=credentials)
    _grpc_server.start()
    yield _grpc_server
    _grpc_server.stop(grace=None)


@pytest.fixture(scope='module')
def my_channel_ssl_credentials(my_ssl_cert_path):
    # If we're using self-signed certificate it's necessarily to pass root certificate to channel
    return grpc.ssl_channel_credentials(
        root_certificates=my_ssl_cert_path.read_bytes()
    )


@pytest.fixture(scope='module')
def grpc_channel(my_channel_ssl_credentials, create_channel):
    """
    Overwrites default `grpc_channel` fixture with ssl credentials
    """
    with create_channel(my_channel_ssl_credentials) as channel:
        yield channel

        
@pytest.fixture(scope='module')
def grpc_authorized_channel(my_channel_ssl_credentials, create_channel):
    """
    Channel with authorization header passed
    """
    grpc_channel_credentials = grpc.access_token_call_credentials("some_token")
    composite_credentials = grpc.composite_channel_credentials(
        my_channel_ssl_credentials,
        grpc_channel_credentials
    )
    with create_channel(composite_credentials) as channel:
        yield channel
    
    
@pytest.fixture(scope='module')
def my_authorized_stub(grpc_stub_cls, grpc_channel):
    """
    Stub with authorized channel
    """
    return grpc_stub_cls(grpc_channel)

Run tests against real gRPC server

Run tests against read grpc server worked in another thread:

py.test
cachedir: .pytest_cache
plugins: grpc-0.0.0
collected 2 items

example/test_example.py::test_some PASSED
example/test_example.py::test_example FAILED

=================================== FAILURES ====================================
_________________________________ test_example __________________________________

grpc_stub = <stub.test_pb2_grpc.EchoServiceStub object at 0x107a9b390>

    def test_example(grpc_stub):
        request = EchoRequest()
>       response = grpc_stub.error_handler(request)

example/test_example.py:35:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.env/lib/python3.7/site-packages/grpc/_channel.py:547: in __call__
    return _end_unary_response_blocking(state, call, False, None)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

state = <grpc._channel._RPCState object at 0x107b263c8>
call = <grpc._cython.cygrpc.SegregatedCall object at 0x107b323c8>
with_call = False, deadline = None

    def _end_unary_response_blocking(state, call, with_call, deadline):
        if state.code is grpc.StatusCode.OK:
            if with_call:
                rendezvous = _Rendezvous(state, call, None, deadline)
                return state.response, rendezvous
            else:
                return state.response
        else:
>           raise _Rendezvous(state, None, None, deadline)
E           grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
E           	status = StatusCode.UNKNOWN
E           	details = "Exception calling application: Some error"
E           	debug_error_string = "{"created":"@1544451353.148337000","description":"Error received from peer","file":"src/core/lib/surface/call.cc","file_line":1036,"grpc_message":"Exception calling application: Some error","grpc_status":2}"
E           >

.env/lib/python3.7/site-packages/grpc/_channel.py:466: _Rendezvous
------------------------------- Captured log call -------------------------------
_server.py                 397 ERROR    Exception calling application: Some error
Traceback (most recent call last):
  File "pytest-grpc/.env/lib/python3.7/site-packages/grpc/_server.py", line 389, in _call_behavior
    return behavior(argument, context), True
  File "pytest-grpc/example/src/servicer.py", line 10, in error_handler
    raise RuntimeError('Some error')
RuntimeError: Some error
================ 1 failed, 1 passed, 1 warnings in 0.16 seconds =================

Run tests directly to python code

Call handlers directly, with fake grpc internals:

py.test --grpc-fake-server

In this case your get nice direct exceptions:

============================= test session starts =============================
cachedir: .pytest_cache
plugins: grpc-0.0.0
collected 2 items

example/test_example.py::test_some PASSED
example/test_example.py::test_example FAILED

================================== FAILURES ===================================
________________________________ test_example _________________________________

grpc_stub = <stub.test_pb2_grpc.EchoServiceStub object at 0x10e06f518>

    def test_example(grpc_stub):
        request = EchoRequest()
>       response = grpc_stub.error_handler(request)

example/test_example.py:35:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pytest_grpc/plugin.py:42: in fake_handler
    return real_method(request, context)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <servicer.Servicer object at 0x10ce75278>, request =
context = <pytest_grpc.plugin.FakeContext object at 0x10e083e48>

    def error_handler(self, request: EchoRequest, context) -> EchoResponse:
>       raise RuntimeError('Some error')
E       RuntimeError: Some error

example/src/servicer.py:10: RuntimeError
=============== 1 failed, 1 passed, 1 warnings in 0.10 seconds ================

Run the servicer on multiple threads

The number of workers threads for gRPC can be specified in two ways:

  • add --grpc-max-workers=<n> to the arguments
  • test modules can also use a grpc_max_workers=<n> variable

See test_blocking in example.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].