Background Image
Table of Contents Table of Contents
Previous Page  383 / 478 Next Page
Information
Show Menu
Previous Page 383 / 478 Next Page
Page Background

(lists.tests.test_views.NewListViewIntegratedTest)

File "/workspace/superlists/lists/views.py", line 30, in new_list2

return redirect(list_)

[...]

TypeError: argument of type 'NoneType' is not iterable

FAILED (errors=3)

Here’s an important lesson to learn about test isolation: it might help you to drive out

good design for individual layers, but it won’t automatically verify the integration

be‐

tween

your layers.

What’s happened here is that the view was expecting the form to return a list item:

lists/views.py.

list_

=

form

.

save

(

owner

=

request

.

user

)

return

redirect

(

list_

)

But we forgot to make it return anything:

lists/forms.py.

def

save

(

self

,

owner

):

if

owner

.

is_authenticated

():

List

.

create_new

(

first_item_text

=

self

.

cleaned_data

[

'text'

],

owner

=

owner

)

else

:

List

.

create_new

(

first_item_text

=

self

.

cleaned_data

[

'text'

])

Thinking of Interactions Between Layers as “Contracts”

Ultimately, even if we had been writing nothing but isolated unit tests, our functional

tests would have picked up this particular slip-up. But ideally we’d want our feedback

cycle to be quicker—functional tests may take a couple of minutes to run, or even a few

hours once your app starts to grow. Is there any way to avoid this sort of problem before

it happens?

Methodologically, the way to do it is to think about the interaction between your layers

in terms of contracts. Whenever we mock out the behaviour of one layer, we have to

make a mental note that there is now an implicit contract between the layers, and that

a mock on one layer should probably translate into a test at the layer below.

Here’s the part of the contract that we missed:

lists/tests/test_views.py.

@patch

(

'lists.views.redirect'

)

def

test_redirects_to_form_returned_object_if_form_valid

(

self

,

mock_redirect

,

mockNewListForm

):

mock_form

=

mockNewListForm

.

return_value

mock_form

.

is_valid

.

return_value

=

True

response

=

new_list2

(

self

.

request

)

Thinking of Interactions Between Layers as “Contracts”

|

355