Verschiedene APIs werden im Web veröffentlicht, und die Anzahl der damit verbundenen Dienste und Programme nimmt von Jahr zu Jahr zu. Gleichzeitig denke ich, dass die Möglichkeiten, Programme und Dienste zu erstellen, die solche APIs verwenden, ebenfalls zunehmen.
Erstellen wir eine einfache Klasse, die tatsächlich Informationen von der Web-API abruft und das Extraktionsergebnis zurückgibt.
sample_api_client.py
from http import client
import json
class SampleApiClient(object):
def __init__(self, base_url):
"""
An Api Client that accesses to resources under specific url.
:param base_url: root url of API server that contains several resources (String)
"""
self.base_url = base_url
def get(self, resource, key='id', value=None):
"""
An method to get entry of specific resources that satisfy following searching option.
:param resource: a relative path from base_url that correspond to resource you want to access.(String)
:param key: an attribute name of resource you want to filter by. default: id (String)
:param value: a value of an attribute you want to filter by. (String)
:return: filtered_data: a result of operation. (Array of Dictionary)
"""
# create connection, and get raw data from API server
conn = client.HTTPConnection(self.base_url, port=80)
conn.request(method='GET', url=('/' + resource))
response = conn.getresponse()
raw_body = response.read()
json_body = json.loads(raw_body.decode(encoding='utf-8'))
# filter if value is specified.
if value is not None:
filtered_data = []
for entry in json_body:
if entry[key] == value:
filtered_data.append(entry)
else:
filtered_data = json_body
return filtered_data
Das Obige ist eine Klasse, die Informationen von der gefälschten Web-API unten erhält.
http://jsonplaceholder.typicode.com/
Dieses Mal werden wir die Methode der obigen Klasse testen. Dies ist eine Methode zum Extrahieren von Elementen, die bestimmten Bedingungen entsprechen, aus der obigen API.
Definieren Sie den Testcode zum Testen dieser Methode wie folgt: In diesem Test testen wir, ob das Akquisitionsergebnis von resource'todos durch einen bestimmten Titel eingegrenzt werden kann. (Zielressource): http://jsonplaceholder.typicode.com/todos/
test_sample_api_client.py
from unittest import TestCase
from bin.sample_api_client import SampleApiClient
# Test Case Definition Starts from here.
class TestSampleApiClient(TestCase):
def test_get_todo_by_title(self):
client = SampleApiClient(base_url='jsonplaceholder.typicode.com')
# a free online REST service that produces some fake JSON data.
result = client.get(resource='todos', key='title', value="delectus aut autem")
expected = [
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": False
}
]
self.assertEqual(expected, result)
Ich werde es tatsächlich ausführen.
python -m unittest test_sample_api_client.py
----------------------------------------------------------------------
Ran 1 test in 0.311s
OK
Auf diese Weise wurde der Test erfolgreich bestanden. Wenn sich andererseits der Status des API-Servers ändert, schlägt der Test möglicherweise fehl. Wenn beispielsweise der Kommunikationspfad zum API-Server fehlschlägt, ist das Ergebnis der Testausführung der folgende Fehler.
======================================================================
ERROR: test_get_todo_by_title (tests.test_sample_api_client.TestSampleApiClient)
----------------------------------------------------------------------
Traceback (most recent call last):
~Kürzung~
OSError: [WinError 10065]Es wurde versucht, eine Socket-Operation auf einem nicht erreichbaren Host auszuführen.
----------------------------------------------------------------------
Ran 1 test in 21.026s
FAILED (errors=1)
Der Komponententest bestätigt die Gültigkeit des Programms als einzelne Einheit, eine solche Testimplementierung wird jedoch vom Verbindungsziel (API-Server) und vom Kommunikationspfad beeinflusst. Wenn ein anderer Benutzer eine Aufgabe mit demselben Titel veröffentlicht, beträgt die Anzahl der Treffer 2, und der Test schlägt fehl, obwohl die Implementierung selbst normal ist.
Eine übliche Methode, um dieses Problem zu umgehen, besteht darin, ein Modell zu erstellen, die zugrunde liegenden Module durch das Modell zu ersetzen und immer einen festen Rückgabewert zu haben. (Details werden in diesem Artikel weggelassen) Beim Erstellen eines Modells ist es jedoch erforderlich, den Rückgabewert des unteren Moduls für jede zu verknüpfende API und Ressource zu definieren und zu verwalten. Mit zunehmender Anzahl von Verknüpfungen wird dies zu einer schwierigen Aufgabe.
Obwohl die Einführung lang geworden ist, werde ich eine Bibliothek namens "vcrpy" einführen, um dieses Problem zu lösen. Mithilfe dieser Bibliothek können an den API-Server gesendete HTTP-Anforderungen / -Antworten in einer Datei aufgezeichnet und wiedergegeben werden, wodurch die Erstellung eines Modells erspart wird.
Installieren Sie zunächst das vcrpy-Modul mit dem folgenden Befehl in Ihrer Umgebung.
pip install vcrpy
Schreiben Sie dann den Testcode neu, um vcrpy zu verwenden.
test_sample_api_client_with_vcr.py
from unittest import TestCase
import vcr
from bin.sample_api_client import SampleApiClient
# Instantiate VCR in order to Use VCR in test scenario.
vcr_instance = vcr.VCR( # Following option is often used.
cassette_library_dir='vcr/cassettes/', # A Location to storing VCR Cassettes
decode_compressed_response=True, # Store VCR content (HTTP Requests / Responses) as a Plain text.
serializer='json', # Store VCR Record as a JSON Data
)
# Test Case Definition Starts from here.
class TestSampleApiClient(TestCase):
@vcr_instance.use_cassette
def test_get_todo_by_title(self):
client = SampleApiClient(base_url='jsonplaceholder.typicode.com')
# a free online REST service that produces some fake JSON data.
result = client.get(resource='todos', key='title', value="delectus aut autem")
expected = [
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": False
}
]
self.assertEqual(expected, result)
Es gibt zwei wesentliche Änderungen:
Nur das. Wenn Sie den Test in diesem Status ausführen, wird der Inhalt der HTTP-Anforderung / Antwort als Datei in dem Verzeichnis aufgezeichnet, das in der Option VCR in der 8. Zeile angegeben ist.
Wenn Sie diesen Test erneut ausführen, erfolgt keine Kommunikation mit dem API-Server. Stattdessen wird die HTTP-Antwort aus dieser Datei gelesen. Versuchen Sie tatsächlich, das Netzwerk erneut zu trennen und den Test erneut auszuführen.
----------------------------------------------------------------------
Ran 1 test in 0.012s
OK
Auf diese Weise ist es mit vcrpy möglich, den Einfluss des Status des gegenüberliegenden Geräts (API-Server) im Unit-Test zu reduzieren. Es ist einfach zu implementieren, probieren Sie es also aus.
Recommended Posts