Repito el mensaje completo porque han pasado casi 5 meses desde el hilo original y habrá gente que no lo haya leído. Comentarios al final.
On 05/01/14 15:08, Andrey Antukh wrote: > > > > El 31 de diciembre de 2013, 10:06, Jesus Cea <[email protected] > <mailto:[email protected]>> escribió: > > Una cosa que he ido descubriendo con los años es que para poder hacer > buenos tests es conveniente que lo que estés probando se preste a > ello. Tienes que programar de forma que lo que haces sea fácilmente > testable. > > El enfoque habitual en otros lenguajes, y mi tendencia en el pasado es > utilizar inyección de dependencias. De hecho hubo una época en la que > di la lata un poco para incluir inyección de dependencias en Python, > pero la respuesta masiva fue que eso era antipitónico y que el futuro > eran los mocks y similares. > > Pero me encuentro que para probar una rutina de 20 lineas escribo 200 > lineas de tests más complejos que la propia rutina a comprobar, el > desarrollo es lento y no puedo evitar pensar que estoy haciendo algo > mal :-). > > Así que, ¿alguien conoce recursos online con consejos prácticos y > ejemplos realistas?. Porque hacer un chequeo mínimamente completo de > esta rutina está siendo un infierno. > > Esta rutina genera una clave al azar e intenta registrarla en un > servidor, que devuelve un 401 mientras un administrador no ha admitido > el registro (y en ese caso devuelve un 200). Una vez que tenemos el > 200, nos guardamos ese usuario y clave en disco y no necesitamos > repetir la operación. > > """ > def consigue_autenticacion() : > # Creamos el fichero si es preciso > open("/tmp/heartbeat", "w").close() > #os.utime("/tmp/heartbeat") > > try : > with open("/local/auth", "r") as f : > token = f.read().strip() > if " " in token : > return # Ya tenemos usuario y clave > except FileNotFoundError : > with open("/dev/urandom", "rb") as f : > token = f.read(4096) > if len(token) != 4096 : > raise RuntimeError("Lectura parcial de entropía") > token = md5(token).hexdigest() > with open("/local/auth", "w") as f : > f.write(token+"\n") > > usuario = "XXXXXX" > clave = "XXXXXXXX" # Confidencial, pero no crítico > auth = requests.auth.HTTPBasicAuth(usuario, clave) > > addr = netifaces.ifaddresses("eth0") > ip_addr = addr[netifaces.AF_INET][0]["addr"] > mac_addr = addr[netifaces.AF_LINK][0]["addr"] > mac_addr = mac_addr[0:2]+mac_addr[3:5]+mac_addr[6:8]+ \ > mac_addr[9:11]+mac_addr[12:14]+mac_addr[15:17] > > factor = 1*60 > while True : > t = time.time() > respuesta = requests.get("https://XXXXXX.jcea.es/registro?" > "ip_addr=%s&mac_addr=%s&ts=%.0f" \ > %(ip_addr, mac_addr, time.time()), > auth = auth, > verify = "XXXXXXXXX.jcea.es.cert", > timeout = 1*60, > headers = {"clave": token}) > os.utime("/tmp/heartbeat") > if respuesta.status_code == 401 : > t = t + factor > factor = factor * 3 > if factor > 3600 : > factor = 3600 > while time.time() < t : > time.sleep(10) > os.utime("/tmp/heartbeat") > continue # Volvemos a intentarlo > elif respuesta.status_code == 200 : > with open("/local/auth", "w") as f : > f.write(mac_addr+" "+token+"\n") > return > else : > raise RuntimeError("El servidor nos devuelve un status %s" \ > %respuesta.status_code) > """ > > El código de testeo de esta rutina es complicado de cojones, feo, > frágil. Uso Mocks para comprobar que las llamadas se realizan en el > orden y con los parámetros correctos, tiro excepciones, simulo > ficheros, etc. La pruebo a fondo. Pero desarrollar el test ha sido > costosísimo. > > ¿Consejos?. > > Se admiten recomendaciones de libros. > > _______________________________________________ > Python-es mailing list > [email protected] <mailto:[email protected]> > https://mail.python.org/mailman/listinfo/python-es > FAQ: http://python-es-faq.wikidot.com/ > > > > Hola. > > La rutina que presentas, es obviamente muy complicada de testear, pero > por que? veamos: > > * Demasiada logica, la funcion es demasiado grande y hace demasiadas > cosas de bajo nivel > * * La logica de generar token tiene que ser otra funcion, que puda ser > mockeada (con un mock tonto de una lambda que devuelve un token dymmy) > * * http, tiene que ser otro metodo que abstraiga de http, tu funcion no > tiene que saber de http, tiene que saber solo de lo que hace, autenticar. > * * la parte de netinterfaces tambien tiene que ser abstraida. > > > Si te fijas, en esta rutina tienes 0 de abstraccion, usas todas las > bibliotecas tal cual con toda la logica adicional que eso implica, > moquear eso es un infierno, pero si ocultas diferentes partes de la > logica con una responsabilidad unica en distintas funciones, probar la > logica concreta de esa rutina (que es seguir unos pasos concretos > llamando a otras rutinas) seria crear 4 mocks llamables de una sola linea. > > La idea final es desacoplar. > > Espero haberme explicado. > Si ves que entenderás mejor con un ejemplo de como haria esta rutina, > puedo hacerte un ejemplo! > > Un saludo. > Andrey Andrey, tu comentario es magnífico. Gracias. La clave, como dices, está en desacoplar, aunque en muchos casos es bastante difícil, como cuando estás probando hardware y no puedes saltarte pasos. Pero toda esta reflexión me ha resultado muy útil, estoy modificando mi estilo para que sea más "comprobable". Muchas gracias por tu mensaje, me ha resultado útil e inspirador. -- Jesús Cea Avión _/_/ _/_/_/ _/_/_/ [email protected] - http://www.jcea.es/ _/_/ _/_/ _/_/ _/_/ _/_/ Twitter: @jcea _/_/ _/_/ _/_/_/_/_/ jabber / xmpp:[email protected] _/_/ _/_/ _/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/ _/_/ _/_/ _/_/ _/_/ "My name is Dump, Core Dump" _/_/_/ _/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Python-es mailing list [email protected] https://mail.python.org/mailman/listinfo/python-es FAQ: http://python-es-faq.wikidot.com/
