Pruebas funcionales en cian



¡Hola!



Mi nombre es Timothy, soy desarrollador de Python en el equipo de la plataforma Cyan Platform. Nuestro equipo desarrolla herramientas para desarrolladores de productos. Estas son bibliotecas: un cliente HTTP, un servidor web, bibliotecas de acceso a bases de datos y herramientas para monitorear microservicios y el sitio en su conjunto, e integración con CI / CD y mucho más.



, — .



...





, , . , , , , , .



, - -. . , - . , , .



Code-coverage



. diff-coverage: pull-request , . — 80%, , pull-request diff-coverage . .



, , , . , , - : diff, :





API-, : dev, beta prod, .



-



coverage — -. ?



-, :



. , , , .



. 2 3 — . , , . , - “” .



- . -, . : — !





, . .



API . API Application Programming Interface, , HTTP API, RabbitMQ / Kafka .



, , HTTP Mock Server, , .





:



  • , API, RabbitMQ, .
  • , .
  • , black box, , .
  • , -.


, Python, C#, frontend NodeJS . Python pytest. Python- -, C#- API-. pytest , .



-?



! , :



  • , -. .
  • . - , — .
  • , -, CI-pipeline .
  • , , , , , .


, .



, API , — -.





, . , app.toml. , :



[[dependency]]
type = "postgres"
alias = "users"

[[dependency]]
type = "rabbitmq"


command line :



cian-functional-test-utils deps up


, docker-compose.yml docker-compose up -d. “” docker-compose, Elasticsearch, . , alias .



conftest.py :



@pytest.fixture(scope='session', autouse=True)
async def start(runner, pg):
    #           ,
    #          health-check.
    await runner.start_background_python_web()
    #       HTTP API,   RabbitMQ , 
    await runner.start_background_python_command('save-users-consumer')

@pytest.fixture(scope='session')
async def pg(postgres_service):
    db = await postgres_service.create_database_by_alias('users')
    #  `pathlib.Path`  .
    await db.execute_scripts(Path('database_schemas') / 'postgres.sql')
    return db


! :



async def test_v1_get_user(http, pg):  #   pg  conftest.py
    # arrange
    await pg.execute('INSERT INTO users (id, name) VALUES (1, "Bart")')
    # act
    response = await http.request('GET', '/v1/get-user/', params={'id': 1})
    # assert
    assert response.status == 200
    assert response.data == {'id': 1, 'name': 'Bart'}


PostgreSQL MsSQL, Cassandra, Redis, Elasticsearch.



HTTP API , :



async def test_save_users_consumer(pg, queue_service):
    # arrange
    #      RabbitMQ ,
    #  ,    .
    await queue_service.wait_consumer(queue='save-users')
    # act
    await queue_service.publish(
        exchange='users',
        routing_key='user.created',
        payload={'id':1, 'name': 'Bart'},
    )
    await asyncio.sleep(0.5)  #  ,    
    # assert
    row = await pg.fetchrow('SELECT name FROM users WHERE id = 1')
    assert row['name'] == 'Bart'


RabbitMQ ( ), . ? RabbitMQ .



, , , .



, . . - API . “” : , HTTP-, Management API. , API, . , .



HTTP-. .



HTTP



HTTP- mountebank. ( ) HTTP. , , :



@pytest.fixture(scope='session')
async def users_mock(http_mock_service):
    #     ,    ,
    #    URL    .
    return await http_mock_service.make_microservice_mock('users')

def test_something(users_mock):
    # arrange
    stub = await users_mock.add_stub(
        method='GET',
        path='/v1/get-user/',
        response=MockResponse(body={'firstName': 'Bart', 'lastName': 'Simpson'}),
    )
    # act
    # do something
    # assert
    # ,        ?userId=234
    request = (await stub.get_requests())[0]
    assert request.params['userId'] == '234'


stub, 404. mountebank . , , 404 , 404, , . , ( 404). , .



mountebank , . . :



  • recordRequests — , , ;
  • --debug — .




, session , HTTP-. start, , autouse=True. - , http-, .



, :



  • , ;
  • statsd graphite ;
  • RabbitMQ , .


, , , , .





, .



, Sphinx. reStructuredText , , , .



:



  • , ;
  • , C#-;
  • ;
  • API Reference, .


, , , .



Type annotations



Python – . , , — . PEP 484.



pytest PyCharm, IDE , :





pytest IDE Jetbrains Python Community Edition. C#- Rider — , IDE, .





, . , Open Source.



, , , :



  • ;
  • ;
  • ;
  • , , -.


- , , , , .



, , , .



.




All Articles