Because TDD is about test-driven design. And functional tests don't do any impact on design.
TDD is about creating code in a way, suitable for unit-testing and creating code step-by-step, keeping each step small and all branches tested.
TDD does these restrictions:
1. don't write line of code until you wrote failing test.
2. don't write line of test until you wrote code that "fixes" failing test.
So, by these restrictions, you will always try to cover all possible branches of your code, all possible different situations and corner-cases. While with functional tests, it's very hard to do that.
I don't think I accept your critique then - I make a clear distinction between "functional" tests (ie, the selenium ones), and "unit" tests, and I write both types
Although you may have a valid point that my "unit" tests aren't unit-ey enough to be called real "unit" tests, because they rely on django and the database - but I still think they serve the correct purpose.
Whatever you call them, they very clearly are written first, before any lines of code, and each line of code is only written in order to fix a failing test.
Maybe you're saying that if my "unit" tests aren't "unit-ey" enough, becauye they are too reliant on Django and the database, they don't work so well in the sense of test-driven design? If so, how?
Let's look at a specific example, ie how to design a model for Polls.
my approach, in pseudocode:
instantiate a model
assign some attributes to it
save it
retrieve it from the database
assert the retrieved object has the attributes assigned earlier, with the correct values & types (including a datetime value)
a more "unit" approach:
instantiate an object
assert it is a subclass of django's model types
assert it has default attributes with correct default types
finally, use some django voodoo or metaclass inspection to confirm that the datetime field, whose default value is "None", is actually a working datetime field...
That last bit is the clincher - in this case, I think particularly due to the datetime field, using a more "unitey" approach actually makes it /harder/ to use TDD to design the object... Whereas using my approach makes it very natural - the test influences the design, because the test uses the object in the way that the code will, the test is a client of the final objects' API, in a more complete way than a "true" unit test would be...
So, I think in this specific case, making tests "more unit-ey" wouldn't help make for better test-driven-design.
I do accept the point that if you're tests aren't isolated from one another, then it's very hard to refactor one area of code without breaking lots of tests in other areas. And I think that where it's my own code, I'm very prepared to spend effort isolating unit tests from each other, using Mocks or whatever else. But when it's Django code, which has a stable API, I'm not that worried by exercising it in unit tests...
TDD is about creating code in a way, suitable for unit-testing and creating code step-by-step, keeping each step small and all branches tested.
TDD does these restrictions:
1. don't write line of code until you wrote failing test.
2. don't write line of test until you wrote code that "fixes" failing test.
So, by these restrictions, you will always try to cover all possible branches of your code, all possible different situations and corner-cases. While with functional tests, it's very hard to do that.