Categorías
Python

Web raspado y arrastra con Scrapy y MongoDB

 

Tabla de contenidos de la unidad

    • e Integración Pruebas – Definido

    • Primeros pasos Configuración
    • Parte 1 – Plano principal
    • Parte 2 – Usuario BlueprintFormsViews
    • Formularios
    • Más Vistos
    • Reflexión
    • la próxima vez
    • Formularios
    • Vistas

    En el último mensaje detallamos cómo validar direcciones de correo electrónico durante el registro del usuario.

    Esta vez, vamos a añadir pruebas de unidad y de integración (yay!) A nuestra aplicación utilizando la extensión matraz de Pruebas, que cubre la mayoría de las características importantes. Este tipo de pruebas se llama viable mínima de Pruebas (o Prueba basada en el riesgo) y está diseñado para probar la funcionalidad de alto riesgo, centrado alrededor de características de la aplicación.

    ¿Se ha perdido el primer puesto? Coge el código desde el repositorio del proyecto para comenzar a trabajar rápidamente. Unidad

    e Integración Pruebas – Definido

    Para los nuevos en la prueba, que es vital para probar las aplicaciones, ya que “las aplicaciones no probadas hacen que sea difícil de mejorar el código y los desarrolladores de aplicaciones no probadas existentes tienden a ser bastante paranoico. Si una aplicación se ha automatizado las pruebas, se puede hacer de manera segura los cambios y al instante saber si se rompe cualquier cosa”(fuente). Las pruebas unitarias

    , por naturaleza, aislados unidades de prueba de código – es decir, funciones individuales – para asegurar que la salida real es la misma que la salida esperada. En muchos casos, ya que a menudo tienen que hacer llamadas a la API externas o tocar una base de datos, pruebas unitarias pueden depender en gran medida de burlarse de datos falsos. Mediante la simulación de las pruebas, es posible que se ejecuten más rápido, pero también pueden ser menos eficaces y son más difíciles de mantener. Debido a esto, no vamos a estar usando burla a menos que absolutamente necesario; en lugar vamos a leer y escribir en la base de datos según sea necesario.

    Tenga en cuenta que cuando una base de datos que se toca en una prueba específica, es técnicamente una prueba de integración ya que la prueba en sí no se limita a una unidad específica. Además, si ejecuta sus pruebas a través de la aplicación Frasco, usando el cliente de prueba ayudante de prueba, se consideran pruebas de integración también.

    Introducción

    A menudo es difícil determinar cómo empezar a probar una aplicación. Una solución a este problema es pensar en su aplicación en términos de funcionalidad usuario final:

    Como se indica en el principio, vamos a escribir sólo las pruebas suficientes para cubrir esta funcionalidad principal. La prueba es dura; somos hiper consciente de eso, así que si sólo está interesado en escribir algunas pruebas, la prueba de lo que más importa. Esto, junto con las pruebas de la cobertura a través de coverage.py, que vamos a detalle en el siguiente artículo de esta serie, vamos a hacer que sea mucho más fácil de estructurar un conjunto de pruebas robusta. Configuración

    activar su virtualenv, a continuación, asegúrese de que se establecen las siguientes variables de entorno:

    $ export APP_SETTINGS="project.config.DevelopmentConfig"
    $ export APP_MAIL_USERNAME="foo"
    $ export APP_MAIL_PASSWORD="bar"

    continuación, ejecutar el conjunto de pruebas actual:

    $ python manage.py test
    test_app_is_development (test_config.TestDevelopmentConfig) ... ok
    test_app_is_production (test_config.TestProductionConfig) ... ok
    test_app_is_testing (test_config.TestTestingConfig) ... ok

    ----------------------------------------------------------------------
    Ran 3 tests in 0.003s

    OK

    Estas pruebas simplemente probar las variables de configuración y el medio ambiente. Deben ser bastante sencillo.

    Para ampliar la suite, tenemos que empezar con una estructura organizada para mantener todo agradable y limpio. Dado que la aplicación ya está estructurado en torno a los planos, vamos a hacer lo mismo para el conjunto de pruebas. Por lo tanto crear dos nuevos archivos de prueba en el directorio “pruebas” – test_main.py y test_user.py – y añadir el siguiente código a cada uno:

    import unittest
    from flask.ext.login import current_user
    from project.util import BaseTestCase

    #
    # Tests go here
    #

    if __name__ == '__main__':
    unittest.main()

    NOTA : También se podría estructurar sus pruebas en todo tipo de prueba – unidad, integración, funcional, etc ..

    Parte 1 – Plano principal

    mirar el código en el archivo views.py (en la carpeta “proyecto / main”), junto con el flujo de trabajo del usuario final, podemos vemos que sólo tenemos que prueba que la ruta principal, /, requiere que el usuario estar conectado a lo que añadir el siguiente código a test_main.py :.

    def test_main_route_requires_login(self):
    # Ensure main route requires a logged in user.
    response = self.client.get('/', follow_redirects=True)
    self.assertTrue(response.status_code == 200)
    self.assertTemplateUsed('user/login.html')

    aquí, estamos afirmando que el código de estado de respuesta es 200 y que se utiliza la plantilla correcta. Ejecutar el banco de pruebas. Todas las 4 pruebas deben pasar.

    Parte 2 – Plano de Usuario

    Hay un poco más en juego en este modelo, por lo que la prueba requerida es mucho más intensa. En esencia, tenemos que probar los puntos de vista y – así, vamos a romper aparte nuestra serie de pruebas en consecuencia. No te preocupes voy a guiar a través de ella. Vamos a crear las 2 clases para asegurar que nuestras pruebas se dividen lógicamente.

    Agregue el código siguiente para test_user.py para que podamos empezar a probar las muchas funciones requeridas.

    class TestUserForms(BaseTestCase):
    pass

    class TestUserViews(BaseTestCase):
    pass

    Formularios

    Tener un registro de usuario es un concepto central en un registro en el programa basado, sin que tenemos una “puerta abierta” a problemas. Este trabajo debe según lo diseñado. Así, siguiendo el flujo de trabajo del usuario, vamos a empezar con el formulario de inscripción . Añadir este código a los TestUserForms () clase.

    def test_validate_success_register_form(self):
    # Ensure correct data validates.
    form = RegisterForm(
    email='new@test.test',
    password='example', confirm='example')
    self.assertTrue(form.validate())

    def test_validate_invalid_password_format(self):
    # Ensure incorrect data does not validate.
    form = RegisterForm(
    email='new@test.test',
    password='example', confirm='')
    self.assertFalse(form.validate())

    def test_validate_email_already_registered(self):
    # Ensure user can't register when a duplicate email is used
    form = RegisterForm(
    email='test@user.com',
    password='just_a_test_user',
    confirm='just_a_test_user'
    )
    self.assertFalse(form.validate())

    En estas pruebas, estamos asegurando que la forma o bien pasa o no basado en la validación de los datos introducidos. Compare esto con el archivo forms.py en la carpeta “/ Proyecto de usuario”. En la última prueba, simplemente estamos registrando el mismo usuario del método setUpClass () de nuestra BaseTestCase en el archivo util.py .

    Mientras estamos probando las formas, vamos a seguir adelante y poner a prueba la forma entrada así:

    def test_validate_success_login_form(self):
    # Ensure correct data validates.
    form = LoginForm(email='test@user.com', password='just_a_test_user')
    self.assertTrue(form.validate())

    def test_validate_invalid_email_format(self):
    # Ensure invalid email format throws error.
    form = LoginForm(email='unknown', password='example')
    self.assertFalse(form.validate())

    Por último, vamos a probar el formulario de cambio de contraseña:

    def test_validate_success_change_password_form(self):
    # Ensure correct data validates.
    form = ChangePasswordForm(password='update', confirm='update')
    self.assertTrue(form.validate())

    def test_validate_invalid_change_password(self):
    # Ensure passwords must match.
    form = ChangePasswordForm(password='update', confirm='unknown')
    self.assertFalse(form.validate())

    def test_validate_invalid_change_password_format(self):
    # Ensure invalid email format throws error.
    form = ChangePasswordForm(password='123', confirm='123')
    self.assertFalse(form.validate())

    Asegúrese de añadir las importaciones requeridas:

    from project.user.forms import RegisterForm, \
    LoginForm, ChangePasswordForm

    Y a continuación, ejecutar las pruebas!

    $ python manage.py test
    test_app_is_development (test_config.TestDevelopmentConfig) ... ok
    test_app_is_production (test_config.TestProductionConfig) ... ok
    test_app_is_testing (test_config.TestTestingConfig) ... ok
    test_main_route_requires_login (test_main.TestMainViews) ... ok
    test_validate_email_already_registered (test_user.TestUserForms) ... ok
    test_validate_invalid_change_password (test_user.TestUserForms) ... ok
    test_validate_invalid_change_password_format (test_user.TestUserForms) ... ok
    test_validate_invalid_email_format (test_user.TestUserForms) ... ok
    test_validate_invalid_password_format (test_user.TestUserForms) ... ok
    test_validate_success_change_password_form (test_user.TestUserForms) ... ok
    test_validate_success_login_form (test_user.TestUserForms) ... ok
    test_validate_success_register_form (test_user.TestUserForms) ... ok

    ----------------------------------------------------------------------
    Ran 12 tests in 1.656s

    Para las pruebas de forma, que, básicamente, sólo una instancia del formulario y llama la función de validación que desencadenará toda la validación, incluyendo nuestro validación personalizada y devolver un valor booleano que indica si los datos del formulario es de hecho válida o no.

    Con nuestras formas probadas, vamos a pasar a las Vistas …

    Vistas

    Inicio y viendo el perfil son partes críticas de la seguridad por lo que queremos para asegurarse de que esto se prueba a fondo.

    entrada: perfil

    def test_correct_login(self):
    # Ensure login behaves correctly with correct credentials.
    with self.client:
    response = self.client.post(
    '/login',
    data=dict(email="test@user.com", password="just_a_test_user"),
    follow_redirects=True
    )
    self.assertTrue(response.status_code == 200)
    self.assertTrue(current_user.email == "test@user.com")
    self.assertTrue(current_user.is_active())
    self.assertTrue(current_user.is_authenticated())
    self.assertTemplateUsed('main/index.html')

    def test_incorrect_login(self):
    # Ensure login behaves correctly with incorrect credentials.
    with self.client:
    response = self.client.post(
    '/login',
    data=dict(email="not@correct.com", password="incorrect"),
    follow_redirects=True
    )
    self.assertTrue(response.status_code == 200)
    self.assertIn(b'Invalid email and/or password.', response.data)
    self.assertFalse(current_user.is_active())
    self.assertFalse(current_user.is_authenticated())
    self.assertTemplateUsed('user/login.html')

    :

    def test_profile_route_requires_login(self):
    # Ensure profile route requires logged in user.
    self.client.get('/profile', follow_redirects=True)
    self.assertTemplateUsed('user/login.html')

    Añadir las importaciones requeridas, así:

    from project import db
    from project.models import User

    registro y resend_confirmation:

    Antes de escribir pruebas para cubrir los puntos de vista de registro y resend_confirmation, echar un vistazo al código. Aviso cómo estamos utilizando la función SEND_EMAIL () del archivo email.py , que envía el correo electrónico de confirmación. Es lo que realmente desea enviar este correo electrónico o debemos fingir usando una biblioteca de burla? Incluso si hacemos enviarlo, es muy difícil afirmar que una muestra de correo electrónico real para arriba en una bandeja de entrada simulado sin la utilización de selenio para levantar la bandeja de entrada real en el navegador. Por lo tanto, vamos a burlan del envío del correo electrónico, lo que vamos a manejar en un artículo posterior.

    confirmar / :

    def test_confirm_token_route_requires_login(self):
    # Ensure confirm/ route requires logged in user.
    self.client.get('/confirm/blah', follow_redirects=True)
    self.assertTemplateUsed('user/login.html')

    Al igual que los dos últimos puntos de vista, las partes restantes de este punto de vista podría ser burlado desde una confirmación token de necesidades que se generen. Sin embargo, sólo podemos generar un token utilizando la función de utilidad del archivo token.py , generate_confirmation_token ():

    def test_confirm_token_route_valid_token(self):
    # Ensure user can confirm account with valid token.
    with self.client:
    self.client.post('/login', data=dict(
    email='test@user.com', password='just_a_test_user'
    ), follow_redirects=True)
    token = generate_confirmation_token('test@user.com')
    response = self.client.get('/confirm/'+token, follow_redirects=True)
    self.assertIn(b'You have confirmed your account. Thanks!', response.data)
    self.assertTemplateUsed('main/index.html')
    user = User.query.filter_by(email='test@user.com').first_or_404()
    self.assertIsInstance(user.confirmed_on, datetime.datetime)
    self.assertTrue(user.confirmed)

    def test_confirm_token_route_invalid_token(self):
    # Ensure user cannot confirm account with invalid token.
    token = generate_confirmation_token('test@test1.com')
    with self.client:
    self.client.post('/login', data=dict(
    email='test@user.com', password='just_a_test_user'
    ), follow_redirects=True)
    response = self.client.get('/confirm/'+token, follow_redirects=True)
    self.assertIn(
    b'The confirmation link is invalid or has expired.',
    response.data
    )

    Añadir las importaciones:

    import datetime
    from project.token import generate_confirmation_token, confirm_token

    y vuelva a ejecutar las pruebas. Uno debe fallar:

    Ran 18 tests in 4.666s

    FAILED (failures=1)

    Esta prueba ha fallado: test_confirm_token_route_invalid_token (). ¿Por qué? Debido a que hay un error en la vista: mal de

    @user_blueprint.route('/confirm/')
    @login_required
    def confirm_email(token):
    try:
    email = confirm_token(token)
    except:
    flash('The confirmation link is invalid or has expired.', 'danger')
    user = User.query.filter_by(email=email).first_or_404()
    if user.confirmed:
    flash('Account already confirmed. Please login.', 'success')
    else:
    user.confirmed = True
    user.confirmed_on = datetime.datetime.now()
    db.session.add(user)
    db.session.commit()
    flash('You have confirmed your account. Thanks!', 'success')
    return redirect(url_for('main.home'))

    ¿Qué?

    En este momento la llamada Flash – por ejemplo, flash ( ‘El enlace de confirmación no es válido o ha caducado.’, ‘Peligro’) – No provoca que la función de salida, por lo que caerá hasta el if / else y confirme la usuario, incluso si la ficha no es válida. Esta es la razón de escribir pruebas.

    Vamos a reescribir la función:

    @user_blueprint.route('/confirm/')
    @login_required
    def confirm_email(token):
    if current_user.confirmed:
    flash('Account already confirmed. Please login.', 'success')
    return redirect(url_for('main.home'))
    email = confirm_token(token)
    user = User.query.filter_by(email=current_user.email).first_or_404()
    if user.email == email:
    user.confirmed = True
    user.confirmed_on = datetime.datetime.now()
    db.session.add(user)
    db.session.commit()
    flash('You have confirmed your account. Thanks!', 'success')
    else:
    flash('The confirmation link is invalid or has expired.', 'danger')
    return redirect(url_for('main.home'))

    Ejecutar las pruebas de nuevo. Los 18 debería pasar.

    ¿Qué pasa si una señal caduca? Escribir una prueba.

    def test_confirm_token_route_expired_token(self):
    # Ensure user cannot confirm account with expired token.
    user = User(email='test@test1.com', password='test1', confirmed=False)
    db.session.add(user)
    db.session.commit()
    token = generate_confirmation_token('test@test1.com')
    self.assertFalse(confirm_token(token, -1))

    Ejecutar las pruebas de nuevo:

    $ python manage.py test
    test_app_is_development (test_config.TestDevelopmentConfig) ... ok
    test_app_is_production (test_config.TestProductionConfig) ... ok
    test_app_is_testing (test_config.TestTestingConfig) ... ok
    test_main_route_requires_login (test_main.TestMainViews) ... ok
    test_validate_email_already_registered (test_user.TestUserForms) ... ok
    test_validate_invalid_change_password (test_user.TestUserForms) ... ok
    test_validate_invalid_change_password_format (test_user.TestUserForms) ... ok
    test_validate_invalid_email_format (test_user.TestUserForms) ... ok
    test_validate_invalid_password_format (test_user.TestUserForms) ... ok
    test_validate_success_change_password_form (test_user.TestUserForms) ... ok
    test_validate_success_login_form (test_user.TestUserForms) ... ok
    test_validate_success_register_form (test_user.TestUserForms) ... ok
    test_confirm_token_route_expired_token (test_user.TestUserViews) ... ok
    test_confirm_token_route_invalid_token (test_user.TestUserViews) ... ok
    test_confirm_token_route_requires_login (test_user.TestUserViews) ... ok
    test_confirm_token_route_valid_token (test_user.TestUserViews) ... ok
    test_correct_login (test_user.TestUserViews) ... ok
    test_incorrect_login (test_user.TestUserViews) ... ok
    test_profile_route_requires_login (test_user.TestUserViews) ... ok

    ----------------------------------------------------------------------
    Ran 19 tests in 5.306s

    OK

    Reflexión

    Esto es probablemente un buen momento para parar y reflexionar, sobre todo porque nos estamos centrando en pruebas mínimas. Recuerde nuestras características fundamentales?

    ¿Estamos cubriendo cada uno de estos? Echemos un vistazo:

    “Los usuarios no registrados deben inscribirse antes de acceder a la aplicación” :

    • test_main_route_requires_login
    • test_validate_email_already_registered
    • test_validate_invalid_email_format
    • test_validate_invalid_password_format
    • test_validate_success_register_form

    “Después de registrar usuarios, un correo electrónico de confirmación es sent- y se consideran usuarios ‘sin confirmar’”

    y:

    ‘usuarios sin confirmar puede conectarse, pero se les redirige inmediatamente a una página que les recuerda a confirmar su cuenta a través de correo electrónico antes de que puedan acceder a la aplicación’:

    • test_validate_success_login_form
    • test_confirm_token_route_expired_token
    • test_confirm_token_route_invalid_token
    • test_confirm_token_route_requires_login
    • test_confirm_token_route_valid_token
    • test_corr ect_login
    • test_incorrect_login
    • test_profile_route_requires_login

    “Una vez confirmado, los usuarios tienen acceso completo al sitio, donde se puede ver la página principal, actualizar su contraseña en la página de perfil, y el cierre de sesión” :

    • test_validate_invalid_change_password
    • test_validate_invalid_change_password_format
    • test_validate_success_change_password_form

    en los ensayos anteriores hemos probado los formularios directamente, y luego también creado pruebas para los puntos de vista (que ejercicio mucho del mismo código que en las pruebas de la forma). ¿Cuáles son las ventajas y desventajas de este tipo de enfoque? Trataremos esto cuando nos atamos en las pruebas de cobertura.

    la próxima vez

    Eso es todo por este post. En los próximos mensajes we’ll- prueba

    feliz!

  • Deja un comentario

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