Pruebas unitarias con django
Upcoming SlideShare
Loading in...5
×
 

Pruebas unitarias con django

on

  • 1,373 views

Charla sobre pruebas unitarias en django

Charla sobre pruebas unitarias en django

Statistics

Views

Total Views
1,373
Views on SlideShare
1,371
Embed Views
2

Actions

Likes
1
Downloads
16
Comments
0

2 Embeds 2

http://www.linkedin.com 1
https://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • 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

Pruebas unitarias con django Pruebas unitarias con django Presentation Transcript

  • Pruebas Unitarias con DjangoTomás Henríquez tchenriquez@gmail.com2-11-2012
  • Historia de las pruebas en el softwarehttp://clearspecs.com/joomla15/downloads/ClearSpecs16V01_GrowthOfSoftwareTest.pdf
  • Historia de las pruebasPeríodo orientado al Debugging (antes - 1956)
  • Historia de las pruebasPeríodo orientado a la demostación (1957 - 1978)
  • Historia de las pruebas
  • Historia de las pruebasPeríodo orientado a la destrucción (1979 - 1982)
  • Historia de las pruebasPeríodo orientado a la evaluación (1983 - 1987)
  • 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”
  • Historia de las pruebasPeríodo orientado a la prevención (1988 - Hoy)
  • Pruebas Unitarias
  • Pruebas¿Cómo uno usualmente prueba su código?
  • Pruebas¿Qué problemas tiene el debugging?
  • Pruebas¿Cómo persistirestas pruebas?
  • Pruebas¡NO ES FÁCIL!
  • Pruebas ¡NO ES FÁCIL!● Carga de datos para la prueba● No debe afectar la base de datos● Super rápidas
  • Sheet Got Serious
  • Carga de datos FIXTURES
  • Carga de datosclass Profession(models.Model): name = models.CharField(max_length=30, unique=True) specialist = models.CharField(max_length=30, blank=True)
  • Carga de datos[ { "pk": 1, "model": "my_app.profession", "fields": { "name": "panadero", "specialist": "pizza", } }, { "pk": 2, "model": "my_app.profession", "fields": { "name": "forever_alone", ... ]
  • 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) <----
  • 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", ... ]
  • 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", ... ]
  • Carga de datos FIXTURES¿Para qué son buenos?
  • Carga de datos Estructura del Appmy_app/ __init__.py models.py fixtures/base.json <------ tests.py
  • 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)
  • Carga de datos Factorieshttps://github.com/dnerdy/factory_boy
  • Carga de datos Factories● Organizado <------
  • 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)
  • 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() ...
  • 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() ...
  • Carga de datos Estructura del Appmy_app/ __init__.py models.py fixtures/base.json factories.py <------- tests.py
  • 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()
  • Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): ReceiptFactory() ...
  • Carga de datos
  • Carga de datos
  • Carga de datos
  • Carga de datos Factories● Organizado● Flexible <-------
  • Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): # No se crea en base de datos ReceiptFactory.build() ...
  • Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): # Crear muchos objects ReceiptFactory.create_batch(5) ...
  • Carga de datos Factories● Organizado● Flexible● Facil de migrar <-------
  • 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))
  • 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()]
  • Carga de datosclass ReceiptTest(TestCase): fixtures = [base.json] def setUp(self): ReceiptFactory() ...
  • MOCKERS http://labix.org/mockerhttp://www.voidspace.org.uk/python/mock/
  • Mockers
  • 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]
  • 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)
  • 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)
  • Buenas y Malas Practicas
  • Tips¿Hacer Pruebas antes de lanzar código?
  • 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])
  • 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)
  • TipsNo hacer multiples pruebas en una función
  • 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)
  • 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 ----------,...
  • 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 ----------,...
  • 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
  • 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)
  • Tips Probar todas las ramasdef handle_coolness(self, user): if user.is_cool: do_cool_stuff(user) else: raise NotCoolDudeException
  • Pruebas de Integración
  • 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)
  • 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)
  • 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)
  • Continuous deployment http://jenkins-ci.org/
  • Continuous Deployment Integrado por django_jenkins Correr Pruebas unitariasVerificacion de codigo (Pep8, jslint, etc) Reportes Emails
  • 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
  • ¿Preguntas?@hazuektchenriquez@gmail.comgithub.com/hassek