Marco Buttu, EuroPython 2015
As an astronomer, I want to interact with the radiotelescope through a command-line interface. When I execute a setup, I want to know if the setup is actually in progress. I also want to know if the setup is done, and in that case I want to know if the telescope is ready to operate. Eventyally, I want to get the actual and the commanded setup.
$ setup KK # Set the K-band receiver (wait a bit...)
$ is_starting
True
$ commanded_setup
KK
$ actual_setup
None
$ is_ready # At some point the setup is completed
True
$ actual_setup
KK
@pytest.fixture
def component():
from myframework import services
return services.get_component('component_name')
def test_setup(component):
component.cli('setup KK')
assert component.cli('is_starting') == 'True'
assert component.cli('commanded_setup') == 'KK'
assert component.cli('actual_setup') == 'None'
wait_until(component.is_ready)
assert component.cli('is_ready') == 'True'
assert component.cli('actual_setup') == 'KK'
@pytest.fixture
def component():
from myframework import get_component
mycomponent = get_component('component_name')
mycomponent.setup('KK')
return mycomponent
def test_is_starting(component):
assert component.is_starting()
wait_until(component.is_ready)
assert not component.is_starting()
@pytest.fixture
def component():
from myframework import get_component
mycomponent = get_component('component_name')
mycomponent.setup('KK')
return mycomponent
def test_setup_set_device_position(component):
expected_pos = component.conf.position()
wait_until(component.is_ready)
actual_pos = component.get_position()
assert math.isclose(actual_pos, expected_pos) # Py3.5
class MyComponent(object):
def __init__(self):
self.device = get_component('low_level_device')
self.conf = Configuration()
def setup(self, setup_code):
# ... At some point:
p = self.conf.get_position(setup_code)
self.device.set_position(p)
Sometimes the external resources are not available during development.
@pytest.fixture
def component():
from myframework import get_component
mycomponent = get_component('component_name')
mycomponent.device.set_position = unittest.mock.MagicMock()
mycomponent.setup('KK')
return component
def test_setup_set_device_position(component):
wait_until(component.is_ready)
expected = component.conf.position('KK')
component.device.set_position.assert_called_with(expected)
The current fanatical TDD experience leads to a primary focus on the unit tests, because those are the tests capable of driving the code design (the original justification for test-first). I don't think that's healthy... Less emphasis on unit tests, because we're no longer doing test-first as a design practice, and more emphasis on, yes, slow, system tests.
Unlike unit tests, the functional tests don't tell you what is broken or where to locate the failure in the code base. They just tell you something is broken. That something could be the test, the browser, or a race condition. There is no way to tell because functional tests, by definition of being end-to-end, test everything.
As with any new plane, the early design phases were riddled with uncertainty. Would the materials be light enough and strong enough? Would the components perform as Airbus desired? Would parts fit together? Would it fly the way simulations predicted? To produce a working aircraft, Airbus had to systematically eliminate those risks using a process it calls a "testing pyramid".