Artículo

Cómo implementar un validador de contraseñas en Python aplicando TDD (I)

Tech & innovation

Cómo implementar un validador de contraseñas en Python aplicando TDD (I)

Hoy en día es muy habitual que nuestras aplicaciones implementen un sistema de autenticación de usuarios. Sin embargo, no siempre nos preocupamos por implementar un sistema de validación de contraseñas, algo que garantice que el usuario introduce una clave lo suficientemente robusta. Siempre hay que realizar validaciones del lado del servidor para estar seguros. Por ello, si estás interesado en implementar un validador de contraseñas, estás de suerte, porque en este post veremos un caso práctico en el que construiremos uno partiendo de cero aplicando TDD. Este ejemplo será implementado en Python, pero es fácilmente extrapolable a cualquier otro lenguaje de programación. El código final está disponible en mi cuenta personal de GitHub. validacion contrasenas python

Empezando por el principio

La primera decisión de diseño que vamos a tomar es la creación de una clase llamada PasswordValidator, que será la que se encargue de la validación de las contraseñas. Para ello, vamos a crear un test que pruebe que podemos instanciar esta clase: [gist id="220c4a41604086e2eb64"] Esto es TDD en su máxima expresión. Antes incluso de verificar la longitud o los caracteres de nuestra contraseña, verificamos que existe una clase llamada PasswordValidator y que la podemos usar. Se podría argumentar que este test no tiene mucho sentido, pero creo que es necesario por dos razones:

  • Este test representa la primera decisión de diseño que vamos a tomar: el nombre de nuestra clase y los parámetros de su constructor. Y puede ocurrir que, dependiendo del caso, ni siquiera sepamos cómo pasar de aquí. Este test nos ayuda a darnos cuenta de eso y a establecer por dónde debemos empezar.
  • Cuando estamos dando nuestros primeros pasos en TDD, la disciplina es importante. Empezar siempre por el test más simple que podamos pensar es una buena forma de ir asimilando la filosofía de TDD e ir ganando soltura.

Dicho esto, es hora de hacer que nuestro test pase. Para ello, crearemos la clase PasswordValidator: [gist id="2a573175bc049b3881f0"] Simplemente hemos creado la clase y su constructor. Con eso, ya tenemos nuestro test en verde.

Validar la longitud

A continuación queremos validar que nuestra contraseña tenga una longitud mínima. Para ello, añadimos el siguiente test: [gist id="4ca51fd7cde7a5fb06e9"] En este test hemos tomado otra decisión en el diseño de nuestra API. Nuestra clase PasswordValidator tendrá un método llamado hasMinimumLength que recibirá dos parámetros: la contraseña y la longitud mínima que debe tener. Para que el test pase, añadiremos el método hasMinimumLength a la clase PasswordValidator: [gist id="52c1f392a650922bcfbb"] Siendo fieles a la filosofía de TDD, éste es el código mínimo que pasa el test. No nos sirve de nada, pero tranquilos, nos encargaremos de eso en breve. Antes de continuar, ¿podemos refactorizar el código que ya tenemos? Pues sí. En el fichero de tests podemos crear un método setUp en el que instanciaremos nuestra clase PasswordValidator, y así eliminaremos la duplicación: [gist id="292630641c169f42c2cf"] De hecho, incluso podemos eliminar el test testItIsInstantiable, porque ya no lo necesitamos. Al fin y al cabo, si no se estuviera instanciando la clase PasswordValidator, el otro test fallaría. También podemos borrar el constructor de esta clase, ya que no está haciendo nada en particular. Tras la refactorización, vamos a crear otro test, que en esta ocasión probará que el método hasMinimumLength devuelve False cuando la contraseña no alcanza la longitud mínima: [gist id="efe2b78c9d0eee554647"] Este test falla porque el método hasMinimumLength se está limitando a devolver True. El código de esta función ahora tiene que pasar los dos tests: [gist id="5a8a011b533b5fa56cf7"] Ya hemos conseguido que nuestra función hasMinimumLength cumpla su cometido. Sin embargo, llegados a este punto, y tras analizar un poco el código, quizá no sea buena idea que la longitud mínima de la contraseña tenga que pasarse por parámetro. Un mejor enfoque sería que ese valor fuera un atributo de la clase PasswordValidator, y que se estableciera de algún modo, por ejemplo en el constructor. Hagamos pues el cambio. Borramos el segundo parámetro de la función en ambos tests y se lo añadimos al constructor de la clase. Los tests fallarán, y para que pasen hay que hacer unos pocos cambios a la clase PasswordValidator: [gist id="d79cf2962965795b0ee6"] El constructor de la clase ha vuelto, y esta vez para quedarse. Guardamos el valor de la longitud mínima en un atributo de la clase, y ese atributo es usado en la función hasMinimumLength, que ahora sólo tiene un parámetro (si descontamos el parámetro self, obligatorio en Python).

¿Y ahora qué?

Ya tenemos una clase que se asegura de que nuestra contraseña tiene un número mínimo de caracteres. ¿Pero cómo nos aseguramos de que tenga letras mayúsculas y minúsculas? ¿Y números? ¿Y caracteres especiales? Todo eso lo podemos implementar siguiendo pautas similares a las que hemos visto en este artículo... Y las veremos en un próximo artículo. ¡No te lo pierdas! :) Si estás interesado en conocer más sobre este tema, puedes encontrar más información en mi cuenta de GitHub.

¡Hablemos!