簡體   English   中英

難以設置消費者測試協議python

[英]difficulty setting up consumer test pact python

我試圖用 Pact 建立消費者測試,但我很掙扎。 如果有人可以幫助我在哪里出錯,將不勝感激。

我要測試的文件如下:

import requests

from orders_service.exceptions import (
    APIIntegrationError,
    InvalidActionError
)


class OrderItem:
    def __init__(self, id, product, quantity, size):
        self.id = id
        self.product = product
        self.quantity = quantity
        self.size = size

    def dict(self):
        return {
            'product': self.product,
            'size': self.size,
            'quantity': self.quantity
        }


class Order:
    def __init__(self, id, created, items, status, schedule_id=None,
                 delivery_id=None, order_=None):
        self._order = order_
        self._id = id
        self._created = created
        self.items = [OrderItem(**item) for item in items]
        self.status = status
        self.schedule_id = schedule_id
        self.delivery_id = delivery_id

    @property
    def id(self):
        return self._id or self._order.id

    @property
    def created(self):
        return self._created or self._order.created

    @property
    def status(self):
        return self._status or self._order.status

    def cancel(self):
        if self.status == 'progress':
            response = requests.get(
                f'http://localhost:3001/kitchen/schedule/{self.schedule_id}/cancel',
                data={'order': self.items}
            )
            if response.status_code == 200:
                return
            raise APIIntegrationError(
                f'Could not cancel order with id {self.id}'
            )
        if self.status == 'delivery':
            raise InvalidActionError(f'Cannot cancel order with id {self.id}')

    def pay(self):
        response = requests.post(
            'http://localhost:3001/payments', data={'order_id': self.id}
        )
        if response.status_code == 200:
            return
        raise APIIntegrationError(
            f'Could not process payment for order with id {self.id}'
        )

    def schedule(self):
        response = requests.post(
            'http://localhost:3000/kitchen/schedule',
            data={'order': [item.dict() for item in self.items]}
        )
        if response.status_code == 201:
            return response.json()['id']
        raise APIIntegrationError(
            f'Could not schedule order with id {self.id}'
        )

    def dict(self):
        return {
            'id': self.id,
            'order': [item.dict() for item in self.items],
            'status': self.status,
            'created': self.created,
        }

消費者測試我只是無法讓它進入發布合同的階段。 有兩個領域我不太熟悉,首先是 python 夾具。 我真的不確定這里需要做什么或如何做到這一點,最后是測試底部的“consumer.cancel()”。

一些幫助讓我設置和一種方式將不勝感激。 這是我為測試寫的:

import atexit
from datetime import datetime
import logging
import os
from uuid import UUID
import requests
import pytest
import subprocess

from pact import Consumer, Like, Provider, Term, Format

from orders_service.orders import Order, OrderItem

log = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

# If publishing the Pact(s), they will be submitted to the Pact Broker here.
# For the purposes of this example, the broker is started up as a fixture defined
# in conftest.py. For normal usage this would be self-hosted or using Pactflow.
PACT_BROKER_URL = "https://xxx.pactflow.io/"
PACT_BROKER_USERNAME = xxx
PACT_BROKER_PASSWORD = xxx

# Define where to run the mock server, for the consumer to connect to. These
# are the defaults so may be omitted
PACT_MOCK_HOST = "localhost"
PACT_MOCK_PORT = 1234

# Where to output the JSON Pact files created by any tests
PACT_DIR = os.path.dirname(os.path.realpath(__file__))


@pytest.fixture
def consumer() -> Order.cancel:
    # return Order.cancel("http://{host}:{port}".format(host=PACT_MOCK_HOST, "port=PACT_MOCK_PORT))
    order = [OrderItem(**{"id":1, "product":"coffee", "size":"big", "quantity":2})]
    payload = Order(id=UUID, created=datetime.now, items=order, status="progress")
    return Order.cancel(payload)



@pytest.fixture(scope="session")
def pact(request):
    """Setup a Pact Consumer, which provides the Provider mock service. This
    will generate and optionally publish Pacts to the Pact Broker"""
    # When publishing a Pact to the Pact Broker, a version number of the Consumer
    # is required, to be able to construct the compatability matrix between the
    # Consumer versions and Provider versions
    # version = request.config.getoption("--publish-pact")
    # publish = True if version else False

    pact = Consumer("UserServiceClient", version=1).has_pact_with(
        Provider("UserService"),
        host_name=PACT_MOCK_HOST,
        port=PACT_MOCK_PORT,
        pact_dir=PACT_DIR,
        publish_to_broker=True,
        broker_base_url=PACT_BROKER_URL,
        broker_username=PACT_BROKER_USERNAME,
        broker_password=PACT_BROKER_PASSWORD,
    )

    pact.start_service()

    # Make sure the Pact mocked provider is stopped when we finish, otherwise
    # port 1234 may become blocked
    atexit.register(pact.stop_service)

    yield pact

    # This will stop the Pact mock server, and if publish is True, submit Pacts
    # to the Pact Broker
    pact.stop_service()

    # Given we have cleanly stopped the service, we do not want to re-submit the
    # Pacts to the Pact Broker again atexit, since the Broker may no longer be
    # available if it has been started using the --run-broker option, as it will
    # have been torn down at that point
    pact.publish_to_broker = False


def test_cancel_scheduled_order(pact, consumer):
        expected = \
       {
          "id": "1e54e244-d0ab-46ed-a88a-b9e6037655ef",
          "order": [
            {
              "product": "coffee",
              "quantity": 1,
              "size": "small"
            }
          ],
          "scheduled": "Wed, 22 Jun 2022 09:21:26 GMT",
          "status": "cancelled"
        }


        (pact
        .given('A scheduled order exists and it is not cancelled already')
        .upon_receiving('a request for cancellation')
        .with_request('get', f'http://localhost:3001/kitchen/schedule/{Like(12343)}/cancel')
        .will_respond_with(200, body=Like(expected)))

        with pact:
            payload = Order(UUID, datetime.now, {"product":"coffee", "size":"large", "quantity":1}, "progress")
            print(payload)
            response = consumer.cancel(payload)
            assert response['status'] == "cancelled"
        
        pact.verify()

我最初也有(改編自協議中的示例):

    # return Order.cancel("http://{host}:{port}".format(host=PACT_MOCK_HOST, "port=PACT_MOCK_PORT))

但我不確定它是如何工作的

謝謝你幫助我

這里有幾個問題:

.with_request('get', f'http://localhost:3001/kitchen/schedule/{Like(12343)}/cancel')
  1. Like匹配器是一個返回對象的函數。 在字符串中添加它可能會在字符串化時導致問題

  2. 您不需要將協議和主機部分放在這里 - 只是路徑,例如:

.with_request(method='GET', path='/kitchen/schedule/bc72e917-4af1-4e39-b897-1eda6d006b18/cancel', headers={'Content-Type': 'application/json'} ...)

如果你想在路徑上使用匹配器,它需要在整個字符串上,例如Regex('/kitchen/schedule/([0-9]+)/cancel') (這不是真正的正則表達式,但希望你明白)。

  1. 我在這段代碼中看不到它調用實際模擬服務的位置。 為了便於閱讀,我刪除了注釋項:
       (pact
        .given('A scheduled order exists and it is not cancelled already')
        .upon_receiving('a request for cancellation')
        .with_request(method='GET', path='/kitchen/schedule/bc72e917-4af1-4e39-b897-1eda6d006b18/cancel', headers={'Content-Type': 'application/json'},)
        .will_respond_with(200, body=Like(expected)))

        with pact:
            # this needs to be sending a request to
            # http://localhost:1234/kitchen/schedule/bc72e917-4af1-4e39-b897-1eda6d006b18/cancel
            response = consumer.cancel() 
        
        pact.verify()

您正在調用的函數的定義不會向 pact 模擬服務發出任何 HTTP 請求,它只是返回一個預設響應。

@pytest.fixture
def consumer() -> Order.cancel:
    # return Order.cancel("http://{host}:{port}".format(host=PACT_MOCK_HOST, "port=PACT_MOCK_PORT))
    order = [OrderItem(**{"id":1, "product":"coffee", "size":"big", "quantity":2})]
    payload = Order(id=UUID, created=datetime.now, items=order, status="progress")
    return Order.cancel(payload)

為了通過 Pact 測試,您需要證明您的代碼實際上使用正確的數據調用了正確的 HTTP 端點,並且您的代碼可以處理它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM