Categorías
Python

de Python 3 f-Strings: una mejor formato de cadenas de sintaxis (Guía)

 

Tabla de Contenidos

  • Primeros pasos
  • refactorización su código en un servicio
  • Sus primeros simulacros
  • Otras formas de parchear
  • que imita el comportamiento de un servicio completo
  • que imita integran funciones de pruebas
  • refactoración a las clases de uso
  • Prueba

  • las actualizaciones de la API de datos
  • condicionalmente probar escenarios
  • Próximos pasos

el siguiente tutorial muestra cómo poner a prueba el uso de una API externa usando Python objetos simulados.

La integración con una aplicación de terceros es una gran manera de ampliar la funcionalidad de su producto.

Sin embargo, el valor añadido también viene con obstáculos. Usted no es dueño de la biblioteca externa, lo que significa que usted no puede controlar los servidores que alojan, el código que comprende su lógica, o los datos que se transfieren entre él y su aplicación. Encima de estas cuestiones, los usuarios están manipulando constantemente los datos a través de sus interacciones con la biblioteca.

Si desea aumentar la utilidad de su aplicación con un API de terceros, entonces usted necesita para estar seguro de que los dos sistemas jugarán agradable. Es necesario que prueba que las dos aplicaciones de interfaz de manera predecible, y necesita que sus pruebas para ejecutar en un entorno controlado. Bono

gratuito: Haga clic aquí para descargar una copia de los «Ejemplos» API REST Guía y obtener una introducción práctica a principios del API Python + REST con ejemplos de acciones concretas.

A primera vista, podría parecer que no tiene ningún control sobre una aplicación de terceros. Muchos de ellos no ofrecen pruebas de servidores. No se puede probar datos en tiempo real, e incluso si se pudiera, las pruebas le proporcione resultados poco fiables ya que los datos se actualiza a través del uso. Además, nunca se quiere que sus pruebas automatizadas para conectarse a un servidor externo. Un error de su parte podría poner fin a su desarrollo, si la liberación de su código depende de si pasar sus pruebas. Afortunadamente, hay una manera de probar la implementación de un API de terceros en un ambiente controlado sin necesidad de conectar realmente a una fuente de datos externa. La solución es falsa la funcionalidad del código externo a través de algo conocido como burla.

Una maqueta es un objeto falso que se construye a lucir y actuar como datos reales. Se intercambia con el objeto real y engañar al sistema para pensar que la maqueta es el verdadero negocio. El uso de un simulacro me recuerda a un tropo clásico de la película donde el héroe agarra un hombre de confianza, se pone el traje, y los pasos en una línea de enemigos que marchan. Nadie se fija en el impostor y todo el mundo se sigue moviendo, como de costumbre.

de autenticación de terceros, tales como OAuth, es un buen candidato para burlarse dentro de su aplicación. OAuth requiere su aplicación para comunicarse con un servidor externo, se trata de datos de usuario real, y su aplicación se basa en su éxito con el fin de obtener acceso a su API. Burlándose de autenticación permite poner a prueba su sistema como un usuario autorizado, sin tener que pasar por el proceso real de intercambio de credenciales. En este caso usted no quiere que verifique si el sistema se autentica correctamente un usuario; que desea probar cómo, después de que han sido autenticados funciones de su aplicación se comportan .

NOTA: Este tutorial usa Python v3.5.1.

Primeros pasos

Comience por la creación de un nuevo entorno de desarrollo para mantener su código de proyecto. Crear un nuevo entorno virtual y luego instalar las siguientes bibliotecas:

$ pip install nose requests

Aquí está un rápido resumen de cada biblioteca que va a instalar, en caso de que no los haya encontrado:

  • La biblioteca de simulacro se utiliza para probar el código Python mediante la sustitución de piezas de su sistema con objetos simulados. NOTA: La biblioteca de simulacro es parte de unittest si está utilizando Python 3.3 o superior. Si está utilizando una versión anterior, por favor, instale la biblioteca backport simulacro.
  • La biblioteca de la nariz se extiende el módulo unittest incorporado en Python para hacer más fácil la prueba. Se pueden usar otras bibliotecas unittest o de terceros, tales como PYtest para lograr los mismos resultados, pero yo prefiero los métodos de la afirmación de la nariz.
  • las peticiones HTTP simplifica en gran medida la biblioteca llama en Python.

Para este tutorial, que se va a comunicar con un API en línea falsa que fue construido para la prueba – JSON marcador de posición. Antes de escribir cualquier prueba, lo que necesita saber qué esperar de la API.

En primer lugar, usted debe esperar que la API que se dirigen en realidad devuelve una respuesta cuando se envía una solicitud. Confirmar esta hipótesis mediante una llamada al punto final con cURL :

$ curl -X GET 'http://jsonplaceholder.typicode.comodos'

Esta llamada debe devolver una lista de JSON-serializado de elementos de tareas. prestar atención a la estructura de los datos de tareas pendientes en la respuesta. Debería ver una lista de objetos con las teclas de ID de usuario, ID, título, validados. Ahora está preparado para hacer su segundo supuesto, ya sabe qué esperar de los datos para que parezca. El punto final de la API está vivo y funcionando. Has demostrado que llamando desde la línea de comandos. Ahora, escribir una prueba la nariz para que pueda confirmar la vida del servidor en el futuro. Mantenlo simple. Sólo debe preocuparse por si el servidor devuelve una respuesta OK. proyecto

/ pruebas / test_todos.py

# Third-party imports...
from nose.tools import assert_true
import requests

def test_request_response():
# Send a request to the API server and store the response.
response = requests.get('http://jsonplaceholder.typicode.comodos')

# Confirm that the request-response cycle completed successfully.
assert_true(response.ok)

Ejecutar la prueba y ver que pasa:

$ nosetests --verbosity=2 project
test_todos.test_request_response ... ok

----------------------------------------------------------------------
Ran 1 test in 9.270s

OK

refactorización su código en un servicio más probable

son buenas que va a llamar a una API externa muchas veces durante su aplicación. Además, esas llamadas a la API probablemente involucrará más lógica que simplemente hacer una petición HTTP, como el procesamiento de datos, manejo de errores, y filtrar. Usted debe tirar el código de su prueba y refactorizar en una función de servicio que encapsula toda la lógica que se esperaba.

reescritura de la prueba para hacer referencia a la función de servicio y para probar la nueva lógica. proyecto

/ pruebas / test_todos.py

# Third-party imports...
from nose.tools import assert_is_not_none

# Local imports...
from project.services import get_todos

def test_request_response():
# Call the service, which will send a request to the server.
response = get_todos()

# If the request is sent successfully, then I expect a response to be returned.
assert_is_not_none(response)

Ejecutar la prueba y ver que falle y luego escribir la cantidad mínima de código para hacerlo pasar:

proyecto / services.py proyecto

# Standard library imports...
try:
from urllib.parse import urljoin
except ImportError:
from urlparse import urljoin

# Third-party imports...
import requests

# Local imports...
from project.constants import BASE_URL

TODOS_URL = urljoin(BASE_URL, 'todos')

def get_todos():
response = requests.get(TODOS_URL)
if response.ok:
return response
else:
return None

/ constants.py

BASE_URL = 'http://jsonplaceholder.typicode.com'

La primera prueba que usted escribió espera una respuesta que se devuelve con un estado OK. Usted refactorizado su lógica de programación en una función de servicio que devuelve la respuesta en sí misma cuando la solicitud al servidor tiene éxito. Un valor Ninguno se devuelve si la petición falla. La prueba incluye ahora una afirmación para confirmar que la función no devuelve Ninguno.

Aviso cómo os dio instrucciones para crear un archivo constants.py y luego rellena con un BASE_URL. La función de servicio se extiende la BASE_URL para crear el TODOS_URL, y desde todos los puntos finales de API utiliza la misma base, se puede seguir creando otros nuevos sin tener que volver a escribir ese trozo de código. Poner el BASE_URL en un archivo separado le permite editar en un solo lugar, lo que será muy útil si hacer referencia a varios módulos de ese código.

Ejecutar la prueba y ver que pasa.

$ nosetests --verbosity=2 project
test_todos.test_request_response ... ok

----------------------------------------------------------------------
Ran 1 test in 1.475s

OK

Su primera maqueta

El código funciona como se esperaba. Esto se sabe porque usted tiene una prueba de paso. Por desgracia, tiene una función de la solución de su servicio aún está accediendo al servidor externo directamente. Cuando se llama a get_todos (), el código está haciendo una petición al punto final de la API y devolver un resultado que depende de que el servidor esté vivo. Aquí, voy a demostrar cómo separar la lógica de la programación de la biblioteca externa real mediante el canje de la solicitud real con una falsa uno que devuelve los mismos datos. proyecto

/ pruebas / test_todos.py

# Standard library imports...
from unittest.mock import Mock, patch

# Third-party imports...
from nose.tools import assert_is_not_none

# Local imports...
from project.services import get_todos

@patch('project.services.requests.get')
def test_getting_todos(mock_get):
# Configure the mock to return a response with an OK status code.
mock_get.return_value.ok = True

# Call the service, which will send a request to the server.
response = get_todos()

# If the request is sent successfully, then I expect a response to be returned.
assert_is_not_none(response)

en cuenta que no he cambiado la función de servicio en absoluto. La única parte del código que he editado fue la prueba en sí. En primer lugar, Importé la función parche () de la biblioteca de simulacro. A continuación, modifica la función de prueba con la función de parche () como un decorador, pasando una referencia a project.services.requests.get. En la función en sí, pasé en un mock_get parámetro, y luego en el cuerpo de la función de prueba, añadí una línea para conjunto mock_get.return_value.ok = True.

Grande. Así que lo que realmente sucede ahora, cuando se ejecuta la prueba? Antes de profundizar en eso, es necesario entender algo sobre la forma en que las peticiones de funcionamiento de la biblioteca. Cuando se llama a la función requests.get (), se realiza una solicitud HTTP detrás de las escenas y luego devuelve una respuesta HTTP en la forma de un objeto Respuesta. La función get () sí se comunica con el servidor externo, por lo que es necesario apuntar a ella. Recuerde que la imagen del héroe intercambiando lugares con el enemigo mientras usa su uniforme? Es necesario para vestir a la maqueta a lucir y actuar como la función requests.get ().

Cuando se ejecuta la función de prueba, se encuentra el módulo en el que se declara la biblioteca de solicitudes, project.services, y que sustituye la función específica, requests.get (), con una maqueta. La prueba también le dice a la maqueta a comportarse de la manera en que la función de servicio espera que actúe. Si nos fijamos en get_todos (), se ve que el éxito de la función depende de si response.ok: devolver True. Eso es lo que la línea mock_get.return_value.ok = True está haciendo. Cuando la propiedad bien se conoce en la maqueta, volverá Verdadero al igual que el objeto real. La función get_todos () devolverá la respuesta, que es la maqueta, y la prueba pasará porque la maqueta no es Ninguno.

Ejecutar la prueba para ver pasar.

$ nosetests --verbosity=2 project

Otras formas de parches

Uso de un decorador es sólo una de varias maneras para parchear una función con una maqueta. En el siguiente ejemplo, parcheo explícitamente una función dentro de un bloque de código, usando un gestor de contexto. La sentencia with patches una función utilizada por cualquier código en el bloque de código. Cuando termina el bloque de código, la función original se restaura. La sentencia with y el decorador lograr el mismo objetivo: Ambos métodos parche project.services.request.get.

proyecto / pruebas / test_todos.py

# Standard library imports...
from unittest.mock import patch

# Third-party imports...
from nose.tools import assert_is_not_none

# Local imports...
from project.services import get_todos

def test_getting_todos():
with patch('project.services.requests.get') as mock_get:
# Configure the mock to return a response with an OK status code.
mock_get.return_value.ok = True

# Call the service, which will send a request to the server.
response = get_todos()

# If the request is sent successfully, then I expect a response to be returned.
assert_is_not_none(response)

Run las pruebas para ver que todavía pasan.

Otra forma de parchear una función es utilizar un parche. Aquí, identifico la fuente de parche, y luego empezar a usar de forma explícita la maqueta. La aplicación de parches no se detiene hasta que diga explícitamente que el sistema deje de usar el simulacro.

proyecto / pruebas / test_todos.py

# Standard library imports...
from unittest.mock import patch

# Third-party imports...
from nose.tools import assert_is_not_none

# Local imports...
from project.services import get_todos

def test_getting_todos():
mock_get_patcher = patch('project.services.requests.get')

# Start patching `requests.get`.
mock_get = mock_get_patcher.start()

# Configure the mock to return a response with an OK status code.
mock_get.return_value.ok = True

# Call the service, which will send a request to the server.
response = get_todos()

# Stop patching `requests.get`.
mock_get_patcher.stop()

# If the request is sent successfully, then I expect a response to be returned.
assert_is_not_none(response)

ejecute nuevamente las pruebas para obtener el mismo resultado exitoso.

Ahora que han visto tres formas de parchear una función con una maqueta, cuándo se debe utilizar cada uno? La respuesta corta: es totalmente de usted. Cada método de aplicación de parches es completamente válido. Una vez dicho esto, he encontrado que los patrones de codificación específicos funcionan especialmente bien con los siguientes métodos de aplicación de parches.

utilizo cada uno de estos métodos en este tutorial, y voy a destacar cada uno como lo introduzco por primera vez.

que imita el comportamiento de un servicio completo

En los ejemplos anteriores, se implementó una maqueta básica y probó una simple afirmación, ya sea los get_todos () de función devuelto Ninguno. La función get_todos () llama a la API externa y recibe una respuesta. Si la llamada tiene éxito, la función devuelve un objeto de respuesta, que contiene una lista serializado en JSON de todos. Si la solicitud no, get_todos () devuelve Ninguno. En el siguiente ejemplo, que muestran cómo se burlan de toda la funcionalidad de get_todos (). Al principio de este tutorial, la llamada inicial se hizo con el servidor mediante cURL devuelve una lista serializado en JSON de diccionarios, lo que representó TODO artículos. Este ejemplo le mostrará cómo burlarse de esos datos.

Recuerde cómo funciona @patch (): Usted proporciona una ruta de acceso a la función que desea para burlarse. La función se encuentra, parche () crea un objeto Mock, y la función real se sustituye temporalmente con la maqueta. Cuando get_todos () es llamado por la prueba, la función utiliza el mock_get de la misma manera que utilizaría el método get real (). Eso significa que las llamadas mock_get como una función, y no espera que retorne un objeto respuesta.

En este caso, el objeto de respuesta es un objeto Respuesta biblioteca solicitudes, que tiene varios atributos y métodos. Falsificaste una de esas propiedades, ok, en un ejemplo anterior. El objeto de respuesta también tiene una función json () que convierte su contenido cadena serializado-JSON en un tipo de datos Python (lista por ejemplo, una o una dict).

proyecto / pruebas / test_todos.py

# Standard library imports...
from unittest.mock import Mock, patch

# Third-party imports...
from nose.tools import assert_is_none, assert_list_equal

# Local imports...
from project.services import get_todos

@patch('project.services.requests.get')
def test_getting_todos_when_response_is_ok(mock_get):
todos = [{
'userId': 1,
'id': 1,
'title': 'Make the bed',
'completed': False
}]

# Configure the mock to return a response with an OK status code. Also, the mock should have
# a `json()` method that returns a list of todos.
mock_get.return_value = Mock(ok=True)
mock_get.return_value.json.return_value = todos

# Call the service, which will send a request to the server.
response = get_todos()

# If the request is sent successfully, then I expect a response to be returned.
assert_list_equal(response.json(), todos)

@patch('project.services.requests.get')
def test_getting_todos_when_response_is_not_ok(mock_get):
# Configure the mock to not return a response with an OK status code.
mock_get.return_value.ok = False

# Call the service, which will send a request to the server.
response = get_todos()

# If the response contains an error, I should get no todos.
assert_is_none(response)

he mencionado en un ejemplo anterior que cuando se ejecutó la función () get_todos que fue parchado con una maqueta, la función devuelve un objeto de burla “respuesta”. Usted puede haber notado un patrón: cada vez que se añade el valor_devuelto a una maqueta, que simulacro se modifica para ser ejecutado como una función, y por defecto devuelve otro objeto de burla. En este ejemplo, he hecho que un poco más claro al declarar explícitamente el objeto Mock, mock_get.return_value = Mock (OK = Verdadero). El mock_get () espejos requests.get (), y requests.get () devuelve una respuesta mientras que mock_get () devuelve un Mock. El objeto de respuesta tiene una propiedad bien, por lo que ha añadido una propiedad bien a la Mock. objeto

La respuesta también tiene una función de JSON (), por lo que añade json a la Mock y adjuntas con un valor_devuelto, ya que será llamado como una función. La función JSON () devuelve una lista de objetos de tareas pendientes. Tenga en cuenta que la prueba incluye ahora una afirmación de que comprueba el valor del response.json (). Usted quiere asegurarse de que los get_todos () devuelve una lista de todos, al igual que el servidor real hace. Por último, para completar el ensayo para get_todos (), añado una prueba para el fracaso.

Ejecutar las pruebas y los ven pasar.

$ nosetests --verbosity=2 project
test_todos.test_getting_todos_when_response_is_not_ok ... ok
test_todos.test_getting_todos_when_response_is_ok ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.285s

OK

que imita las funciones integradas

los ejemplos que he demostrar que ha sido bastante sencillo, y en el siguiente ejemplo, que se sumará a la complejidad. Imagine un escenario en el que se crea una nueva función de servicio que llama get_todos () y luego filtra los resultados para devolver sólo los elementos de tareas que se han completado. Qué tiene que burlarse de la requests.get () de nuevo? No, en este caso se burlan de los get_todos () funciona directamente! Recuerde, cuando se burla de una función, que está reemplazando el objeto real con el simulacro, y sólo tiene que preocuparse acerca de cómo interactúa la función de servicio con ese simulacro. En el caso de get_todos (), usted sabe que no toma parámetros y que devuelve una respuesta con un JSON () la función que devuelve una lista de objetos de tareas pendientes. No te importa lo que sucede bajo el capó; que sólo se preocupa de que los get_todos () devuelve simulacros de lo que esperan los get_todos reales () para el retorno. proyecto

/ pruebas / test_todos.py

# Standard library imports...
from unittest.mock import Mock, patch

# Third-party imports...
from nose.tools import assert_list_equal, assert_true

# Local imports...
from project.services import get_uncompleted_todos

@patch('project.services.get_todos')
def test_getting_uncompleted_todos_when_todos_is_not_none(mock_get_todos):
todo1 = {
'userId': 1,
'id': 1,
'title': 'Make the bed',
'completed': False
}
todo2 = {
'userId': 1,
'id': 2,
'title': 'Walk the dog',
'completed': True
}

# Configure mock to return a response with a JSON-serialized list of todos.
mock_get_todos.return_value = Mock()
mock_get_todos.return_value.json.return_value = [todo1, todo2]

# Call the service, which will get a list of todos filtered on completed.
uncompleted_todos = get_uncompleted_todos()

# Confirm that the mock was called.
assert_true(mock_get_todos.called)

# Confirm that the expected filtered list of todos was returned.
assert_list_equal(uncompleted_todos, [todo1])

@patch('project.services.get_todos')
def test_getting_uncompleted_todos_when_todos_is_none(mock_get_todos):
# Configure mock to return None.
mock_get_todos.return_value = None

# Call the service, which will return an empty list.
uncompleted_todos = get_uncompleted_todos()

# Confirm that the mock was called.
assert_true(mock_get_todos.called)

# Confirm that an empty list was returned.
assert_list_equal(uncompleted_todos, [])

en cuenta que ahora estoy parcheo la función de prueba para buscar y reemplazar project.services.get_todos con una maqueta. La función simulacro debe devolver un objeto que tiene una función JSON (). Cuando se llama, la función de JSON () debe devolver una lista de objetos de tareas pendientes. También agrego una afirmación que confirmar que la función get_todos () se llama en realidad. Esto es útil para establecer que cuando la función de servicio tiene acceso a la API actual, la función de los get_todos reales () se ejecutará. Aquí, también incluyo un examen para verificar que si get_todos () devuelve Ninguno, los get_uncompleted_todos () devuelve la función de una lista vacía. Una vez más, confirmo que los get_todos función () se llama.

Escribir las pruebas, ejecutarlos ver que fallan, y luego escribir el código necesario para hacerlas pasar.

proyecto / services.py

def get_uncompleted_todos():
response = get_todos()
if response is None:
return []
else:
todos = response.json()
return [todo for todo in todos if todo.get('completed') == False]

las pruebas sobre su pasaje.

Refactoring pone a prueba a utilizar las clases

Usted probablemente ha notado que algunas de las pruebas parece pertenecer juntos en un grupo. Tiene dos pruebas que golpean las get_todos función (). Sus otras dos pruebas se centran en get_uncompleted_todos (). Cada vez que comienzo a las tendencias de anuncios y similitudes entre las pruebas, les refactorizar en una clase de prueba. Esta refactorización logra varias metas:

en cuenta que yo uso la técnica de parche para burlarse de las funciones específicas de las clases de prueba. Como ya he mencionado antes, este método de parches es ideal para la creación de una maqueta que abarca más de varias funciones. El código en el método teardown_class () restaura explícitamente el código original cuando las pruebas terminen.

proyecto / pruebas / test_todos.py

# Standard library imports...
from unittest.mock import Mock, patch

# Third-party imports...
from nose.tools import assert_is_none, assert_list_equal, assert_true

# Local imports...
from project.services import get_todos, get_uncompleted_todos

class TestTodos(object):
@classmethod
def setup_class(cls):
cls.mock_get_patcher = patch('project.services.requests.get')
cls.mock_get = cls.mock_get_patcher.start()

@classmethod
def teardown_class(cls):
cls.mock_get_patcher.stop()

def test_getting_todos_when_response_is_ok(self):
# Configure the mock to return a response with an OK status code.
self.mock_get.return_value.ok = True

todos = [{
'userId': 1,
'id': 1,
'title': 'Make the bed',
'completed': False
}]

self.mock_get.return_value = Mock()
self.mock_get.return_value.json.return_value = todos

# Call the service, which will send a request to the server.
response = get_todos()

# If the request is sent successfully, then I expect a response to be returned.
assert_list_equal(response.json(), todos)

def test_getting_todos_when_response_is_not_ok(self):
# Configure the mock to not return a response with an OK status code.
self.mock_get.return_value.ok = False

# Call the service, which will send a request to the server.
response = get_todos()

# If the response contains an error, I should get no todos.
assert_is_none(response)

class TestUncompletedTodos(object):
@classmethod
def setup_class(cls):
cls.mock_get_todos_patcher = patch('project.services.get_todos')
cls.mock_get_todos = cls.mock_get_todos_patcher.start()

@classmethod
def teardown_class(cls):
cls.mock_get_todos_patcher.stop()

def test_getting_uncompleted_todos_when_todos_is_not_none(self):
todo1 = {
'userId': 1,
'id': 1,
'title': 'Make the bed',
'completed': False
}
todo2 = {
'userId': 2,
'id': 2,
'title': 'Walk the dog',
'completed': True
}

# Configure mock to return a response with a JSON-serialized list of todos.
self.mock_get_todos.return_value = Mock()
self.mock_get_todos.return_value.json.return_value = [todo1, todo2]

# Call the service, which will get a list of todos filtered on completed.
uncompleted_todos = get_uncompleted_todos()

# Confirm that the mock was called.
assert_true(self.mock_get_todos.called)

# Confirm that the expected filtered list of todos was returned.
assert_list_equal(uncompleted_todos, [todo1])

def test_getting_uncompleted_todos_when_todos_is_none(self):
# Configure mock to return None.
self.mock_get_todos.return_value = None

# Call the service, which will return an empty list.
uncompleted_todos = get_uncompleted_todos()

# Confirm that the mock was called.
assert_true(self.mock_get_todos.called)

# Confirm that an empty list was returned.
assert_list_equal(uncompleted_todos, [])

Ejecutar las pruebas. Todo debería pasar porque no introduce ninguna nueva lógica. Usted simplemente movido código por todas partes.

$ nosetests --verbosity=2 project
test_todos.TestTodos.test_getting_todos_when_response_is_not_ok ... ok
test_todos.TestTodos.test_getting_todos_when_response_is_ok ... ok
test_todos.TestUncompletedTodos.test_getting_uncompleted_todos_when_todos_is_none ... ok
test_todos.TestUncompletedTodos.test_getting_uncompleted_todos_when_todos_is_not_none ... ok

----------------------------------------------------------------------
Ran 4 tests in 0.300s

OK
Prueba

de cambios a los datos API

A lo largo de este tutorial he estado demostrando cómo se burlan de datos devueltos por una API de terceros. Que los datos simulacro se basa en la suposición de que los datos reales utiliza el mismo contrato de datos como lo está imitando. Su primer paso fue hacer una llamada a la API actual y tomando nota de los datos que se devuelven. Puede ser bastante seguros de que la estructura de los datos no han cambiado en el poco tiempo que ha estado trabajando a través de estos ejemplos, sin embargo, no debe estar seguro de que los datos permanecerán sin cambios siempre. Cualquier buena librería externa se actualiza regularmente. Mientras que los desarrolladores tienen como objetivo hacer compatible con versiones nuevo código, con el tiempo, llega un momento en que está en desuso código.

Como se puede imaginar, confiando enteramente en datos falsos es peligroso. Puesto que usted está probando su código sin comunicarse con el servidor real, puede convertirse fácilmente en un exceso de confianza en la fuerza de sus pruebas. Cuando llegue el momento de utilizar la aplicación con datos reales, todo se desmorona. La siguiente estrategia se debe utilizar para confirmar que los datos que se espera de servidor coincide con los datos que se está probando. El objetivo aquí es comparar la estructura de datos (por ejemplo, las claves en un objeto) en lugar de los datos reales.

Observe cómo estoy usando el gestor de contexto técnica de aplicación de parches. A continuación, es necesario llamar al servidor real y que necesita para burlarse de él por separado.

proyecto / pruebas / test_todos.py

def test_integration_contract():
# Call the service to hit the actual API.
actual = get_todos()
actual_keys = actual.json().pop().keys()

# Call the service to hit the mocked API.
with patch('project.services.requests.get') as mock_get:
mock_get.return_value.ok = True
mock_get.return_value.json.return_value = [{
'userId': 1,
'id': 1,
'title': 'Make the bed',
'completed': False
}]

mocked = get_todos()
mocked_keys = mocked.json().pop().keys()

# An object from the actual API and an object from the mocked API should have
# the same data structure.
assert_list_equal(list(actual_keys), list(mocked_keys))

Sus pruebas deben pasar. Su estructura de datos burlado coincide con el de la API actual.

condicionalmente escenarios de ensayo de

Ahora que tiene una prueba para comparar los contratos de datos reales con los burlaron queridos, lo que necesita saber cuándo ejecutarlo. La prueba que incide en el servidor real no debe ser automatizado debido a un fallo no significa necesariamente que su código es malo. Puede que no seas capaz de conectar con el servidor real en el momento de la ejecución de pruebas para una docena de razones que están fuera de su control. Ejecutar esta prueba por separado de sus pruebas automatizadas, sino también ejecutarlo con bastante frecuencia. Una forma de omitir selectivamente pruebas es utilizar una variable de entorno como una palanca. En el siguiente ejemplo, todas las pruebas se ejecutan a menos que la variable de entorno SKIP_REAL se establece en True. Cuando la variable SKIP_REAL se activa en, se omitirá cualquier prueba con el decorador @skipIf (SKIP_REAL). / Pruebas / test_todos.py proyecto

# Standard library imports...
from unittest import skipIf

# Local imports...
from project.constants import SKIP_REAL

@skipIf(SKIP_REAL, 'Skipping tests that hit the real API server.')
def test_integration_contract():
# Call the service to hit the actual API.
actual = get_todos()
actual_keys = actual.json().pop().keys()

# Call the service to hit the mocked API.
with patch('project.services.requests.get') as mock_get:
mock_get.return_value.ok = True
mock_get.return_value.json.return_value = [{
'userId': 1,
'id': 1,
'title': 'Make the bed',
'completed': False
}]

mocked = get_todos()
mocked_keys = mocked.json().pop().keys()

# An object from the actual API and an object from the mocked API should have
# the same data structure.
assert_list_equal(list(actual_keys), list(mocked_keys))

proyecto / constants.py

# Standard-library imports...
import os

BASE_URL = 'http://jsonplaceholder.typicode.com'
SKIP_REAL = os.getenv('SKIP_REAL', False)
$ export SKIP_REAL=True

ejecutar las pruebas y prestar atención a la salida. Una prueba fue ignorado y que la consola muestre el mensaje, “Omisión de pruebas que llegan al servidor de la API real”. ¡Excelente!

$ nosetests --verbosity=2 project
test_todos.TestTodos.test_getting_todos_when_response_is_not_ok ... ok
test_todos.TestTodos.test_getting_todos_when_response_is_ok ... ok
test_todos.TestUncompletedTodos.test_getting_uncompleted_todos_when_todos_is_none ... ok
test_todos.TestUncompletedTodos.test_getting_uncompleted_todos_when_todos_is_not_none ... ok
test_todos.test_integration_contract ... SKIP: Skipping tests that hit the real API server.

----------------------------------------------------------------------
Ran 5 tests in 0.240s

OK (SKIP=1)

Próximos pasos

En este punto, usted ha visto cómo probar la integración de la aplicación con un API de terceros mediante simulacros. Ahora que ya sabe cómo abordar el problema, puede seguir practicando escribiendo funciones de servicio que para los otros puntos finales de API en JSON marcador de posición (por ejemplo, mensajes, comentarios, usuarios). Bono

gratuito: Haga clic aquí para descargar una copia de los «Ejemplos» API REST Guía y obtener una introducción práctica a principios del API Python + REST con ejemplos de acciones concretas.

Mejore sus habilidades aún más mediante la conexión de su aplicación a una verdadera biblioteca externa, como Google, Facebook o Evernote y ver si se puede escribir pruebas que se burla de uso. Seguir produciendo código limpio y fiable y que permanezca atento a la siguiente tutorial, que describirá cómo tomar las pruebas al siguiente nivel con los servidores de simulacros!

Coge el código desde el repositorio.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *