prueba sun it arias con django

Post on 22-Dec-2015

221 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Tomás Henríquez2-11-2012tchenriquez@gmail.com

TRANSCRIPT

Pruebas Unitarias con Django Tomás Henríquez tchenriquez@gmail.com 2-11-2012

Historia de las pruebas

en el software

http://clearspecs.com/joomla15/downloads/ClearSpecs16V01_GrowthOfSoftwareTest.pdf

Historia de las pruebas

Período orientado al Debugging

(antes - 1956)

Historia de las pruebas

Período orientado a la demostación

(1957 - 1978)

Historia de las pruebas

Historia de las pruebas

Período orientado a la destrucción

(1979 - 1982)

Historia de las pruebas

Perí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 pruebas

Perí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 persistir

estas 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 datos

class 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 datos

class 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 App

my_app/

__init__.py

models.py

fixtures/base.json <------

tests.py

Carga de datos

class 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

Factories

https://github.com/dnerdy/factory_boy

Carga de datos

Factories● Organizado <------

Carga de datos

from django.db import models

class 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 datos

class 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 datos

class 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 App

my_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, EmbeddedDocument

class 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 datos

class 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/mocker

http://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, KWARGS

class 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)

Mockers

from mocker import Mocker, ARGS, KWARGS

class 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 MalasPracticas

Tips

¿Hacer Pruebas antes de lanzar código?

TipsMALMAL

def 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'])

TipsBIENBIEN

def test_gmail(self): strips = ('---------- Forwarded message ----------', 'Fwd: ', 'From: ', 'Date: ', 'Subject: ', 'To: ') checks = {'subject': u'SeamlessWeb 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)

Tips

No hacer multiples pruebas en una función

TipsMALMAL

def test_emails(self): strips = ('---------- Forwarded message ----------', 'Fwd: ', 'From: ', 'Date: ', 'Subject: ', 'To: ') checks = {'subject': u'SeamlessWeb 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)

TipsBIENBIEN

def test_gmail(self): strips = ('---------- Forwarded message ----------', 'Fwd: ', 'From: ', 'Date: ', 'Subject: ', 'To: ') checks = {'subject': u'SeamlessWeb 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 ----------',...

TipsBIENBIEN

def test_gmail(self): strips = ('---------- Forwarded message ----------', 'Fwd: ', 'From: ', 'Date: ', 'Subject: ', 'To: ') checks = {'subject': u'SeamlessWeb 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 ----------',...

TipsPruebas por AserciónPruebas por Aserción

def test_gmail_checks(self): checks = {'subject': u'SeamlessWeb Order'}

gmail = message.objects.get(id=1) msgs = strip_forwarding(gmail) for key, val in checks.items(): self.assertEqual(val, msg[key]) <---- Asercion def 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

TipsPruebas por AcciónPruebas por Acción

def test_gmail(self): strips = ('---------- Forwarded message ----------', 'Fwd: ', 'From: ', 'Date: ', 'Subject: ', 'To: ') checks = {'subject': u'SeamlessWeb 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)

TipsProbar todas las ramasProbar todas las ramas

def handle_coolness(self, user): if user.is_cool: do_cool_stuff(user) else: raise NotCoolDudeException

Pruebas de Integración

Pruebas de Integracióndjango client librarydjango client library

def 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óndjango client librarydjango client library

def 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ónWebTest!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 unitarias

Verificacion de codigo (Pep8, jslint, etc)

Reportes

Emails

Continuous Deployment

if 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?

@hazuek

tchenriquez@gmail.com

github.com/hassek

top related