¿panacea del desarrollo o pérdida de tiempo?
Israel Saeta Pérez
@dukebody en todas partes
+10.000 backend + 5.000 frontend tests solamente en sistemas principales
DiversIT
PyConES 2021
¿quieres participar? escríbeme
coste
beneficio
def foo_bar_baz(number):
if number % 2 == 0 and number % 3 == 0:
return "baz"
if number % 2 == 0:
return "foo"
elif number % 3 == 0:
return "bar"
else:
return None
def test_foo():
number = 2 # preparación
result = foo_bar_baz(number) # ejecución
assert result == "foo" # validación
def test_foo():
number = 6
result = foo_bar_baz(number)
assert result == "baz"
componente
función/clase
servicio entero
frontend + backend
selenium
cypress
unittest+framework
pact
unittest
TDD >>> que tu código tenga tests
TDD = que los tests sean los que guíen el código
def add_1(number):
return number + 2
@pytest.mark.parametrize("number", [1, 3, -5])
def test_add_1(number):
assert add_1(number) = number + 2
import get_builder
def build_something():
builder = get_builder()
builder.build()
@mock.patch("myfile.get_builder")
def test_build_something(mock_get_builder):
build_something()
assert mock_get_builder().build.called
def do_whatever():
logger.info("Doing whatever!")
return True
@mock.patch("myfile.logger_info")
def test_do_whatever_logging(mock_logger_info):
do_whatever()
mock_logger_info.assert_called_with("Doing whatever!")
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def test_person_str():
person = Person("Alberto")
assert str(person) == "Alberto"
def get_order():
return ["A", "B", "C"]
def test_order():
assert get_order() == ["A", "B", "C"]
import os
from unittest import mock
def is_active():
if os.getenv("SERVICE_ACTIVE", False):
return True
return False
@mock.patch("os.getenv")
def test_activated(mock_getenv):
mock_getenv.return_value = True
assert is_active() is True
@mock.patch("os.getenv")
def test_deactivated(mock_getenv):
mock_getenv.return_value = False
assert is_active() is False
from datetime import datetime
from unittest import mock
def view(request):
start = request.GET["start"]
end = request.GET["end"]
return get_data(start=start, end=end)
def get_data(since, until):
return {
"since": since.isoformat(),
"until": until.isoformat()
}
@mock.patch("__main__.get_data")
def test_view(get_data):
start = datetime(2020, 2, 10)
end = datetime(2020, 2, 11)
request = mock.Mock(
GET={"start": start, "end": end}
)
view(request)
get_data.assert_called_with(start=start, end=end)
escribe los tests con la perspectiva de alguien que no ha escrito el código o se enfrenta a revisarlo
empieza por el nivel más alto razonable y crea tests más unitarios sólo si tiene sentido en el diseño real del programa
evita escribir tests unitarios que sean triviales o sólo prueben la implementación - no te ayudarán a refactorizar!
más valor cuanto más cerca de requisito real