<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">El 31 de diciembre de 2013, 10:06, Jesus Cea <span dir="ltr"><<a href="mailto:jcea@jcea.es" target="_blank">jcea@jcea.es</a>></span> escribió:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">-----BEGIN PGP SIGNED MESSAGE-----<br>
Hash: SHA1<br>
<br>
Una cosa que he ido descubriendo con los años es que para poder hacer<br>
buenos tests es conveniente que lo que estés probando se preste a<br>
ello. Tienes que programar de forma que lo que haces sea fácilmente<br>
testable.<br>
<br>
El enfoque habitual en otros lenguajes, y mi tendencia en el pasado es<br>
utilizar inyección de dependencias. De hecho hubo una época en la que<br>
di la lata un poco para incluir inyección de dependencias en Python,<br>
pero la respuesta masiva fue que eso era antipitónico y que el futuro<br>
eran los mocks y similares.<br>
<br>
Pero me encuentro que para probar una rutina de 20 lineas escribo 200<br>
lineas de tests más complejos que la propia rutina a comprobar, el<br>
desarrollo es lento y no puedo evitar pensar que estoy haciendo algo<br>
mal :-).<br>
<br>
Así que, ¿alguien conoce recursos online con consejos prácticos y<br>
ejemplos realistas?. Porque hacer un chequeo mínimamente completo de<br>
esta rutina está siendo un infierno.<br>
<br>
Esta rutina genera una clave al azar e intenta registrarla en un<br>
servidor, que devuelve un 401 mientras un administrador no ha admitido<br>
el registro (y en ese caso devuelve un 200). Una vez que tenemos el<br>
200, nos guardamos ese usuario y clave en disco y no necesitamos<br>
repetir la operación.<br>
<br>
"""<br>
def consigue_autenticacion() :<br>
# Creamos el fichero si es preciso<br>
open("/tmp/heartbeat", "w").close()<br>
#os.utime("/tmp/heartbeat")<br>
<br>
try :<br>
with open("/local/auth", "r") as f :<br>
token = f.read().strip()<br>
if " " in token :<br>
return # Ya tenemos usuario y clave<br>
except FileNotFoundError :<br>
with open("/dev/urandom", "rb") as f :<br>
token = f.read(4096)<br>
if len(token) != 4096 :<br>
raise RuntimeError("Lectura parcial de entropía")<br>
token = md5(token).hexdigest()<br>
with open("/local/auth", "w") as f :<br>
f.write(token+"\n")<br>
<br>
usuario = "XXXXXX"<br>
clave = "XXXXXXXX" # Confidencial, pero no crítico<br>
auth = requests.auth.HTTPBasicAuth(usuario, clave)<br>
<br>
addr = netifaces.ifaddresses("eth0")<br>
ip_addr = addr[netifaces.AF_INET][0]["addr"]<br>
mac_addr = addr[netifaces.AF_LINK][0]["addr"]<br>
mac_addr = mac_addr[0:2]+mac_addr[3:5]+mac_addr[6:8]+ \<br>
mac_addr[9:11]+mac_addr[12:14]+mac_addr[15:17]<br>
<br>
factor = 1*60<br>
while True :<br>
t = time.time()<br>
respuesta = requests.get("<a href="https://XXXXXX.jcea.es/registro" target="_blank">https://XXXXXX.jcea.es/registro</a>?"<br>
"ip_addr=%s&mac_addr=%s&ts=%.0f" \<br>
%(ip_addr, mac_addr, time.time()),<br>
auth = auth,<br>
verify = "XXXXXXXXX.jcea.es.cert",<br>
timeout = 1*60,<br>
headers = {"clave": token})<br>
os.utime("/tmp/heartbeat")<br>
if respuesta.status_code == 401 :<br>
t = t + factor<br>
factor = factor * 3<br>
if factor > 3600 :<br>
factor = 3600<br>
while time.time() < t :<br>
time.sleep(10)<br>
os.utime("/tmp/heartbeat")<br>
continue # Volvemos a intentarlo<br>
elif respuesta.status_code == 200 :<br>
with open("/local/auth", "w") as f :<br>
f.write(mac_addr+" "+token+"\n")<br>
return<br>
else :<br>
raise RuntimeError("El servidor nos devuelve un status %s" \<br>
%respuesta.status_code)<br>
"""<br>
<br>
El código de testeo de esta rutina es complicado de cojones, feo,<br>
frágil. Uso Mocks para comprobar que las llamadas se realizan en el<br>
orden y con los parámetros correctos, tiro excepciones, simulo<br>
ficheros, etc. La pruebo a fondo. Pero desarrollar el test ha sido<br>
costosísimo.<br>
<br>
¿Consejos?.<br>
<br>
Se admiten recomendaciones de libros.<br>
<br>
- --<br>
Jesús Cea Avión _/_/ _/_/_/ _/_/_/<br>
<a href="mailto:jcea@jcea.es">jcea@jcea.es</a> - <a href="http://www.jcea.es/" target="_blank">http://www.jcea.es/</a> _/_/ _/_/ _/_/ _/_/ _/_/<br>
Twitter: @jcea _/_/ _/_/ _/_/_/_/_/<br>
jabber / <a href="mailto:xmpp%3Ajcea@jabber.org">xmpp:jcea@jabber.org</a> _/_/ _/_/ _/_/ _/_/ _/_/<br>
"Things are not so easy" _/_/ _/_/ _/_/ _/_/ _/_/ _/_/<br>
"My name is Dump, Core Dump" _/_/_/ _/_/_/ _/_/ _/_/<br>
"El amor es poner tu felicidad en la felicidad de otro" - Leibniz<br>
-----BEGIN PGP SIGNATURE-----<br>
Version: GnuPG v1.4.15 (GNU/Linux)<br>
Comment: Using GnuPG with Thunderbird - <a href="http://www.enigmail.net/" target="_blank">http://www.enigmail.net/</a><br>
<br>
iQCVAwUBUsKJG5lgi5GaxT1NAQLu7wQAlG+qzPwUIZWi0wLtgXBg44WWMbODuqZd<br>
SQrsSxFxEL5GHhyWiW2RCJ7cG5B9Sgtbfg2Sez0o9PiAwFxMku42DxTJwS/tPTpK<br>
15I9WUuvN2lylAOvMPvn5CuUsuis2wQ0R2hv5jgXPJ39Kl/e2ncwuiZB83J1APvd<br>
5jZXkbYoTz8=<br>
=9H+8<br>
-----END PGP SIGNATURE-----<br>
_______________________________________________<br>
Python-es mailing list<br>
<a href="mailto:Python-es@python.org">Python-es@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-es" target="_blank">https://mail.python.org/mailman/listinfo/python-es</a><br>
FAQ: <a href="http://python-es-faq.wikidot.com/" target="_blank">http://python-es-faq.wikidot.com/</a><br>
</blockquote></div><br><br>Hola.</div><div class="gmail_extra"><br></div><div class="gmail_extra">La rutina que presentas, es obviamente muy complicada de testear, pero por que? veamos:</div><div class="gmail_extra"><br>
</div><div class="gmail_extra">* Demasiada logica, la funcion es demasiado grande y hace demasiadas cosas de bajo nivel</div><div class="gmail_extra">* * 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)</div>
<div class="gmail_extra">* * 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.</div><div class="gmail_extra">* * la parte de netinterfaces tambien tiene que ser abstraida.</div>
<div class="gmail_extra"><br></div><div class="gmail_extra"><br></div><div class="gmail_extra">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.</div>
<div class="gmail_extra"><br></div><div class="gmail_extra">La idea final es desacoplar.</div><div class="gmail_extra"><br></div><div class="gmail_extra">Espero haberme explicado.</div><div class="gmail_extra">Si ves que entenderás mejor con un ejemplo de como haria esta rutina, puedo hacerte un ejemplo!</div>
<div class="gmail_extra"><br></div><div class="gmail_extra">Un saludo.</div><div class="gmail_extra">Andrey</div><div class="gmail_extra"><br><br><br clear="all"><div><br></div>-- <br>Andrey Antukh - Андрей Антух - <<a href="mailto:niwi@niwi.be" target="_blank">niwi@niwi.be</a>><br>
<a href="http://www.niwi.be/about.html" target="_blank">http://www.niwi.be/about.html</a><br><a href="http://www.kaleidos.net/A5694F/" target="_blank">http://www.kaleidos.net/A5694F/</a><br><br>"Linux is for people who hate Windows, BSD is for people who love UNIX"<br>
"Social Engineer -> Because there is no patch for human stupidity"
</div></div>