Your SlideShare is downloading. ×
Pruebas unitarias con django
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Pruebas unitarias con django

1,147
views

Published on

Charla sobre pruebas unitarias en django

Charla sobre pruebas unitarias en django

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,147
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
21
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Make sure it runs Make sure it solves the problem
  • Una ves las aprendes a hacer, siempre es mas rapido hace Pruebas que persistan
  • Buscar foto que me ayude con el texto Crear info inicial Que no afecte tu base de datos Super Fast!
  • Buscar foto que me ayude con el texto Crear info inicial Que no afecte tu base de datos Super Fast!
  • Colorizar este codigo
  • Colorizar este codigo
  • Colorizar este codigo
  • Colorizar este codigo
  • Colorizar este codigo
  • Transcript

    • 1. Pruebas Unitarias con DjangoTomás Henríquez tchenriquez@gmail.com2-11-2012
    • 2. Historia de las pruebas en el softwarehttp://clearspecs.com/joomla15/downloads/ClearSpecs16V01_GrowthOfSoftwareTest.pdf
    • 3. Historia de las pruebasPeríodo orientado al Debugging (antes - 1956)
    • 4. Historia de las pruebasPeríodo orientado a la demostación (1957 - 1978)
    • 5. Historia de las pruebas
    • 6. Historia de las pruebasPeríodo orientado a la destrucción (1979 - 1982)
    • 7. Historia de las pruebasPeríodo orientado a la evaluación (1983 - 1987)
    • 8. Historia de las pruebas“Ninguna técnica puede garantizar software sin errores, sin embargo, un conjunto de técnicas cuidadosamente elegidas para un proyecto en específico puede ayudar a asegurar el desarrollo y mantenimiento de software de calidad para un proyecto”
    • 9. Historia de las pruebasPeríodo orientado a la prevención (1988 - Hoy)
    • 10. Pruebas Unitarias
    • 11. Pruebas¿Cómo uno usualmente prueba su código?
    • 12. Pruebas¿Qué problemas tiene el debugging?
    • 13. Pruebas¿Cómo persistirestas pruebas?
    • 14. Pruebas¡NO ES FÁCIL!
    • 15. Pruebas ¡NO ES FÁCIL!● Carga de datos para la prueba● No debe afectar la base de datos● Super rápidas
    • 16. Sheet Got Serious
    • 17. Carga de datos FIXTURES
    • 18. Carga de datosclass Profession(models.Model): name = models.CharField(max_length=30, unique=True) specialist = models.CharField(max_length=30, blank=True)
    • 19. Carga de datos[ { "pk": 1, "model": "my_app.profession", "fields": { "name": "panadero", "specialist": "pizza", } }, { "pk": 2, "model": "my_app.profession", "fields": { "name": "forever_alone", ... ]
    • 20. Carga de datosclass Profession(models.Model): name = models.CharField(max_length=30, unique=True) specialist = models.CharField(max_length=30, blank=True) full_time = models.BooleanField(default=False) <----
    • 21. Carga de datos[ { "pk": 1, "model": "my_app.profession", "fields": { "name": "panadero", "specialist": "pizza", "full_time": false, <--- Ay no..... } }, { "pk": 2, "model": "my_app.profession", "fields": { "name": "forever_alone", ... ]
    • 22. Carga de datos[ { "pk": 1, "model": "my_app.profession", "fields": { "name": "panadero", "specialist": "pizza", "full_time": false, <--- Ay no..... } }, { "pk": 2, "model": "my_app.profession", "fields": { "name": "forever_alone", ... ]
    • 23. Carga de datos FIXTURES¿Para qué son buenos?
    • 24. Carga de datos Estructura del Appmy_app/ __init__.py models.py fixtures/base.json <------ tests.py
    • 25. Carga de datosclass UserTest(TestCase): fixtures = [base.json] def setUp(self): pass def tearDown(self): pass def test_coolness(self): # usuario con id == 1 existe gracias al fixture user = User.objects.get(id=1) self.assertTrue(user.is_cool, False) user.become_a_hipster() self.assertTrue(user.is_cool, True)
    • 26. Carga de datos Factorieshttps://github.com/dnerdy/factory_boy
    • 27. Carga de datos Factories● Organizado <------
    • 28. Carga de datosfrom django.db import modelsclass Receipt(models.Model): user_id = fields.IntegerField() merchant = fields.CharField(max_length=30)class ReceiptItem(models.Model): name = models.CharField(max_length=30) quantity = models.IntegerField(default=1) alert_sent = models.BooleanField(default=False) receipt = models.ForeignKey(Receipt)class Attach(models.Model): name = models.CharField(max_length=30) item = models.ForeignKey(ReceiptItem)
    • 29. Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): rep = Receipt(user_id=1, merchant=mami) rep.save() ri = ReceiptItem(name=medias, quantity=2, receipt=rep) ri.save() att = Attach(name=foto_de_juanita.jpg, item=ri) att.save() ...
    • 30. Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): rep = Receipt(user_id=1, merchant=mami) rep.save() ri = ReceiptItem(name=medias, quantity=2) ri.save() att = Attach(name=foto_de_juanita.jpg, item=ri) att.save() ...
    • 31. Carga de datos Estructura del Appmy_app/ __init__.py models.py fixtures/base.json factories.py <------- tests.py
    • 32. Carga de datosclass ReceiptFactory(factory.Factory): FACTORY_FOR = Receipt user_id = 1 merchant = "mami"class ReceiptItemFactory(factory.Factory): FACTORY_FOR = ReceiptItem name = factory.Sequence(lambda n: item-%s % n) quantity = 1 receipt = ReceiptFactory()class AttachmentFactory(factory.Factory): FACTORY_FOR = Attachment name = factory.Sequence(lambda n: attachment-%s % n) item = ReceiptItemFactory()
    • 33. Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): ReceiptFactory() ...
    • 34. Carga de datos
    • 35. Carga de datos
    • 36. Carga de datos
    • 37. Carga de datos Factories● Organizado● Flexible <-------
    • 38. Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): # No se crea en base de datos ReceiptFactory.build() ...
    • 39. Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): # Crear muchos objects ReceiptFactory.create_batch(5) ...
    • 40. Carga de datos Factories● Organizado● Flexible● Facil de migrar <-------
    • 41. Carga de datosfrom mongoengine.document import Document, EmbeddedDocumentclass Attach(EmbeddedDocument): name = fields.StringField(required=True)class ReceiptItem(EmbeddedDocument): name = fields.StringField(required=True) quantity = fields.DecimalField(default=Decimal(1)) alert_sent = fields.BooleanField(default=False) attachments = fields.ListField(fields.EmbeddedDocumentField(Attach))class Receipt(Document): user_id = fields.IntField(required=True) merchant = fields.StringField(required=True) items = fields.ListField(fields.EmbeddedDocumentField(ReceiptItem))
    • 42. Carga de datosclass AttachmentFactory(factory.Factory): FACTORY_FOR = Attachment name = factory.Sequence(lambda n: attachment-%s % n)class ReceiptItemFactory(factory.Factory): FACTORY_FOR = ReceiptItem name = factory.Sequence(lambda n: item-%s % n) quantity = 1 Attachments = [AttachmentFactory.build()]class ReceiptFactory(factory.Factory): FACTORY_FOR = Receipt user_id = 2 merchant = "Amazon" items = [ReceiptItemFactory.build()]
    • 43. Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): ReceiptFactory() ...
    • 44. MOCKERS http://labix.org/mockerhttp://www.voidspace.org.uk/python/mock/
    • 45. Mockers
    • 46. Mockersdef tweet(tokens, body): consumer = oauth.Consumer(TWITTER_KEY, settings.TWITTER_SECRET) token = oauth.Token(tokens.oauth, tokens.oauth_secret) client = oauth.Client(consumer, token) header, body = client.request("http://api.twitter.com/1/statuses/" "update.json", "POST", body="status=%s" % body) if header[status] == 401: return False, (Twitter account not authorized. Please connect your account again.) body = json.loads(body) if header[status] != 200: return False, body.get(error, Unknown Twitter error) return True, sbody[id_str]
    • 47. Mockersfrom mocker import Mocker, ARGS, KWARGSclass TweetTest(TestCase): fixtures = [base.json] def setUp(self): mocker = Mocker() mock_client = mocker.replace(oauth.Client) mock_client.request(ARGS, KWARGS) mocker.response({code: 200, text: OK, description: Success!}) <---- self.mocker = mocker def test_tweet(self): user = User.objects.get(id=1) self.assertTrue(user.tweets, 0) with self.mocker: res = tweet(user.tokens, esto es un Tweet de prueba) self.assertEquals(res, True)
    • 48. Mockersfrom mocker import Mocker, ARGS, KWARGSclass TweetTest(TestCase): fixtures = [base.json] def setUp(self): mocker = Mocker() mock_client = mocker.replace(oauth.Client) mock_client.request(ARGS, KWARGS) mocker.throw(ConnectionException) <---- self.mocker = mocker def test_tweet(self): user = User.objects.get(id=1) # Podemos manejar la excepcion? with self.mocker: tweet(user.tokens, esto es un Tweet de prueba)
    • 49. Buenas y Malas Practicas
    • 50. Tips¿Hacer Pruebas antes de lanzar código?
    • 51. Tips MALdef test_gmail(self): expected_msg = { subject: SeamlessWeb Order, plain: [image: Seamless Web Logo] ... # MAL html: n<table width="640" border=... # MAL } m = Message.objects.get(pk=1) msg = { subject: m.subject, html: m.body_mimetype_html, plain: m.body_mimetype_plain } msg = strip_forwarding(msg) self.assertEqual(msg[subject], expected_msg[subject]) self.assertEqual(msg[plain], expected_msg[plain]) self.assertEqual(msg[html], expected_msg[html])
    • 52. Tips BIENdef test_gmail(self): strips = (---------- Forwarded message ----------, Fwd: , From: , Date: , Subject: , To: ) checks = {subject: uSeamlessWeb Order} msg = strip_forwarding(msg) # Validar que los valores sean los esperados for key, val in checks.items(): self.assertEqual(val, msg[key]) # Asegurar que estos valores no se encuentren en el email for strip in strips: for m in msg.values(): self.assertNotIn(strip, m)
    • 53. TipsNo hacer multiples pruebas en una función
    • 54. Tips MALdef test_emails(self): strips = (---------- Forwarded message ----------, Fwd: , From: , Date: , Subject: , To: ) checks = {subject: uSeamlessWeb Order} gmail, aol, hotmail = message.objects.all()[:2] msgs = (strip_forwarding(gmail), strip_forwarding(aol), strip_forwarding(hotmail)) for msg in msgs: for key, val in checks.items(): self.assertEqual(val, msg[key]) for strip in strips: for m in msg.values(): self.assertNotIn(strip, m)
    • 55. Tips BIENdef test_gmail(self): strips = (---------- Forwarded message ----------, Fwd: , From: , Date: , Subject: , To: ) checks = {subject: uSeamlessWeb Order} gmail = message.objects.get(id=1) msgs = strip_forwarding(gmail) for key, val in checks.items(): self.assertEqual(val, msg[key]) for strip in strips: for m in msg.values(): self.assertNotIn(strip, m)def test_aol(self): strips = (---------- Forwarded message ----------,...
    • 56. Tips BIENdef test_gmail(self): strips = (---------- Forwarded message ----------, Fwd: , From: , Date: , Subject: , To: ) checks = {subject: uSeamlessWeb Order} gmail = message.objects.get(id=1) msgs = strip_forwarding(gmail) for key, val in checks.items(): self.assertEqual(val, msg[key]) for strip in strips: for m in msg.values(): self.assertNotIn(strip, m)def test_aol(self): strips = (---------- Forwarded message ----------,...
    • 57. Tips Pruebas por Asercióndef test_gmail_checks(self): checks = {subject: uSeamlessWeb Order} gmail = message.objects.get(id=1) msgs = strip_forwarding(gmail) for key, val in checks.items(): self.assertEqual(val, msg[key]) <---- Aserciondef test_gmail_strips(self): strips = (---------- Forwarded message ----------, Fwd: , From: , Date: , Subject: , To: ) gmail = message.objects.get(id=1) msgs = strip_forwarding(gmail) for strip in strips: for m in msg.values(): self.assertNotIn(strip, m) <---- Asercion
    • 58. Tips Pruebas por Accióndef test_gmail(self): strips = (---------- Forwarded message ----------, Fwd: , From: , Date: , Subject: , To: ) checks = {subject: uSeamlessWeb Order} gmail = message.objects.get(id=1) msgs = strip_forwarding(gmail) <---- ACCION for key, val in checks.items(): self.assertEqual(val, msg[key]) for strip in strips: for m in msg.values(): self.assertNotIn(strip, m)
    • 59. Tips Probar todas las ramasdef handle_coolness(self, user): if user.is_cool: do_cool_stuff(user) else: raise NotCoolDudeException
    • 60. Pruebas de Integración
    • 61. Pruebas de Integración django client librarydef test_view(self): user = User.objects.get(id=1) url = /login/ response = self.client.post(url, { username: user.username, password: fakybaby, timezone: America/Caracas } self.assertEquals(response.status_code, 200) self.assertEquals(response.cookies_set[logged_name], User.username)
    • 62. Pruebas de Integración django client librarydef test_view(self): user = User.objects.get(id=1) url = /login/ response = self.client.post(url, { username: user.username, password: fakybaby, timezone: America/Caracas } self.assertEquals(response.status_code, 200) self.assertEquals(response.cookies_set[logged_name], User.username)
    • 63. Pruebas de Integración WebTest!def test_view(self): user = User.objects.get(id=1) url = /login/ form = self.app.get(url).forms[login-form] form[username] = user.username form[password] = fakybaby response = form.submit().follow() self.assertEquals(response.status_code, 200) self.assertEquals(response.cookies_set[logged_name], user.username)
    • 64. Continuous deployment http://jenkins-ci.org/
    • 65. Continuous Deployment Integrado por django_jenkins Correr Pruebas unitariasVerificacion de codigo (Pep8, jslint, etc) Reportes Emails
    • 66. Continuous Deploymentif len(sys.argv) > 1 and sys.argv[1] in [test, jenkins]: # test mongo db MONGO_DBNAME = db_test db = mongoengine.connect(MONGO_DBNAME, username=MONGO_USERNAME, password=MONGO_PASSWORD, host=MONGO_HOST, port=MONGO_PORT, safe=True) db.drop_database(MONGO_DBNAME) # drop entire database
    • 67. ¿Preguntas?@hazuektchenriquez@gmail.comgithub.com/hassek