2. Quien soy?
Test Architect en SCRM (Lidl Group)
11 Años experiencia en Software Testing
10 años experiencia en Automation Testing
Python
Java
Javascript
Ruby
Retrogamer y amante de los comics
9. Estructura Test Unitario
Arrange
Parte donde se configura e inicializa el Test unitario
Act
Es la parte donde se ejecuta el código del Test unitario
Assert
Es la parte donde se valida el resultado del Test unitario
10. Buenas prácticas
Independencia entre tests
Nombre descriptivo de los tests
Cada test solo prueba una cosa
Implementar Test Doubles para las dependencias
13. Mocking es el proceso por el cual el test decide la
implementación y comportamiento que tendrán las
dependencias de la clase que se va a probar.
14. Porque hacer mocks?
Elimina dependencias en el componente que estamos probando
Permiten testear métodos o funciones que no retornan ningún valor
permite poder probar errores
Reduce la complejidad de los tests (unitarios, de componente o de integración)
Posibilita desarrollar la clase sin esperar a que el resto de componentes estén acabados.
15. Dummies
Son dobles de test usados como
parámetros obligatorios de un
elemento con los que no se quiere
interactuar.
Suelen ser objetos vacíos ya que
no se van a utilizar directamente
en el test.
16. Fake
Son implementaciones de
componentes funcionales y
operativas pero con lo
mínimo necesario para
realizar los tests.
Los tests no tienen control
sobre estos.
17. Mock
Son dobles de tests que son
capaces de analizar la relación
entre el componente que
estamos probando y sus
interacciones.
Nos ayuda a saber el análisis
del comportamiento del
componente que estamos
probando.
18. Spy
Se utilizan también para
analizar la relación entre el
componente que estamos
probando y sus
interacciones pero sin
sustituir al objeto real.
19. Stub
Es un componente que tiene
un comportamiento
predefinido y que se utiliza
para responder a las llamadas
del componente que estamos
probando.
Este componente sustituye al
objeto real
20.
21. Dummy example
class SuperPower():
name = None
def __init__(self, name):
self.name = name
def use(self):
print('Super Power Used')
class SuperHero:
first_name = None
second_name = None
def __init__(self, first_name, second_name, super_power):
self.first_name = first_name
self.second_name = second_name
self.super_power = super_power
def get_first_name(self):
return self.first_name
def get_second_name(self):
return self.second_name
def get_full_name(self):
return self.first_name + ' ' + self.second_name
def attack(self):
self.super_power.use()
import pytest
from unittest.mock import sentinel
from src.dummy import SuperHero
def test_super_hero():
hero = SuperHero(first_name='Doctor', second_name='Strange' ,
super_power=sentinel)
print(hero.get_full_name())
22. Lo que une el desarrollo que no lo
separen las pruebas
23. Problema
Necesitamos un método que retorne a un candidato aleatorio:
No puedes ser tu mismo
No puedes ser alguien que hayas visto anteriormente
24. Función a testear
import random
users = ['Sara', 'Alexandra']
def get_next_person(user):
person = get_random_user()
while person in user['people_seen']:
person = get_random_user()
return person
def get_random_user():
return random.choice(users)
25. Unit Test
from src.next_person import get_next_person
def test_new_person():
# Arrange
user = {'people_seen': []}
expected_person = 'Alexandra'
# Action
actual_person = get_next_person(user)
# Assert
assert actual_person == expected_person
33. Problema TinDevQA Match
Cuando el usuario le gusta a una persona…
Si el otro usuario le gusta
Mandar un mail a ambos usuarios
Cuando el otro usuario no le gusta
Mandar un mail de no me gusta de forma civilizada
Si el otro usuario no lo ha evaluado
Decir que espere que el otro usuario le evalue
34. Evaluar Match
def evaluate(self, person1, person2):
if person1 in person2['likes']:
self.send_email(person1)
self.send_email(person2)
elif person1 in person2['dislikes']:
self.let_down_gently(person1)
elif person1 not in person2['likes']
and person1 not in person2['dislikes']:
self.give_it_time(person1)
NO RETURNS!!!!!
35. Comprobar que se ha llamado el
método
@patch.object(TindevQA, "let_down_gently")
def test_person2_dislikes_person1(mock_let_down):
app = TindevQA()
person1 = 'Luke'
person2 = {'name': 'Leia',
'likes': ['Han Solo'],
'dislikes': ['Luke']}
app.evaluate(person1, person2)
assert mock_let_down.call_count == 1
52. Integration Test
def send_sms(self, user, text, to):
try:
body = {'from': user, 'text': text, 'to': to,
'api_key': ‘XXXXXX', 'api_secret: ‘XXXXXXXXX'}
r = requests.post(url=URL, data=body)
return r
except Timeout:
return "ERROR"
Mandar SMS a un usuario
53. Integration Test
def test_send_sms():
app = TindevQA()
user = 'Chewbacca'
text = 'Quieres enredarte entre mis pelos?'
to = 34600000000
response = app.send_sms(user, text, to)
assert response.ok == True
54. Integration test Mocking
def test_send_sms_with_mockito():
app = TindevQA()
user = 'Chewbacca'
text = 'Quieres enredarte entre mis pelos?'
response_mock = mock({'status_code': 200, 'text': 'Ok'})
when(requests).post(...).thenReturn(response_mock)
response = app.send_sms(user, text)
assert response.status_code == 200
56. Create tu propio mock
@app.post("/sms/json")
@app.post("/sms/json")
def send_sms():
body = {'from': request.forms.get("from"),
'text': request.forms.get("text"),
'to': request.forms.get("to")}
requests_handled.append(body)
if len(response_saved) > 0:
response_to_send = response_saved.pop()
response.status = response_to_send['status_code']
return response_to_send['message']
57. Funciones para “espiar” y devolver
respuestas predefinidas
@app.post("/set_response")
def set_response():
body = b"".join(request.body)
body = json.loads(body)
response_saved.append(body)
@app.get("/stats")
def stats():
body = {'requests': list(requests_handled)}
return json.dumps(body)
58. Test usando nuestro propio mock
def test_send_sms():
app = TindevQA()
user = 'Chewbacca'
text = 'Quieres enredarte entre mis pelos?'
response = app.send_sms(user, text)
r = requests.get('http://localhost:8080/stats')
body = r.json()
assert body['requests'][0]['from'] == 'Chewbacca'
assert body['requests'][0]['to'] == ‘34000000000'
assert body['requests'][0]['text'] == 'Quieres enredarte entre mis pelos?'
59. Test forzando una respuesta errónea
def test_send_sms_with_error():
app = TindevQA()
user = 'Chewbacca'
text = 'Quieres enredarte entre mis pelos?'
data = {'status_code': 500, 'message': 'Servidor Caido'}
r = requests.post('http://localhost:8080/set_response', json=data)
response = app.send_sms(user, text)
assert response.status_code == 500
assert response.text == 'Servidor Caido'
60. Resumen
Los mocks nos ayudan a escribir tests unitarios más
simples
Eliminan dependencias
Verifican comportamiento de métodos sin retorno
Nos permiten testear errores
Nos permiten testear más rápido
Nos permiten testear sin que el resto de componentes
estén finalizados