DHH either is being disingenuous, or badly misunderstands unit testing.
He opens with this:
> The classical definition of a unit test in TDD lore is one that doesn't touch the database. Or any other external interface, like the file system. The justification is largely one of speed. Connecting to external services like that would be too slow to get the feedback cycle you need.
No, "unit tests" in TDD -- and long before, TDD didn't change anything about the definition -- are tests that, to the extent practical, test all and only the functionality of the specific unit under test, hence the name. That's the reason why external interactions are minimized in proper unit tests (whether or not TDD is being practiced). TDD observes that such tests are generally fast, and builds the red-green-refactor cycle around that fact, but speed isn't the justification for the isolation, isolation of the functionality being tested from other functionality is the point of unit testing (which is designed not only to identify errors, but to pinpoint them.)
He also seems to misunderstand TDD - which is more about design than testing. Unit testing and TDD are not synonymous. You can, and I certainly do, test-drive code over traditional unit test boundaries.
> He also seems to misunderstand TDD - which is more about design than testing. Unit testing and TDD are not synonymous.
Actually I think it's more his critics which misunderstand this—he argues against TDD, and he doesn't think unit testing is sufficient, but he doesn't argue against testing, or unit testing.
> he argues against TDD, and he doesn't think unit testing is sufficient
But what he describes as "TDD" to argue against it isn't TDD (either in his description of its substance or his description of its rationale), and what he describes as "unit testing" to argue that it isn't sufficient isn't unit testing (again, either in substance or rationale.)
> but he doesn't argue against testing, or unit testing.
He specifically argues that unit testing should be deemphasized if not outright eliminated, and that the reason for this is the elimination of test-first as a design practice. So, yes, he does argue against unit testing (of course, the argument is nonsense, since unit testing was an important practice before test-first practices, and test-first practices are independent of kind of testing -- sure, TDD emphasizes unit test first, but ATDD/BDD focus on acceptance test first; moving toward or away from test-first as a practice is completely orthogonal to the degree of focus on unit testing vs. other kinds of testing.)
You argue that the database should be thought of as a separate unit, and that unit tests should minimize interactions outside their unit. But this argument proves too much; it would also argue that unit tests should avoid using the memory allocator.
Your parent said "to the extent practical". Limiting interaction with external units as fundamental as the memory allocator is far from practical. I actually think DHH would agree with the "to the extent practical", but would think limiting DB access in tests of fundamentally DB-dependent things like ActiveRecord models is impractical. I think the debate is fundamentally about that practicality, and neither side is obviously right.
I think it's impractical to test things that use ActiveRecord without testing the database.
ActiveRecord at its core is meant to generate and run SQL and give you object graphs back, and you need to test that the SQL it generates is correct and does the right thing.
> I think it's impractical to test things that use ActiveRecord without testing the database.
I think one of the fundamental, if not really directly addressed, divides between the sides here is over the question of whether domain models "using" (being tightly coupled to) the persistence layer is sensible architecture even outside of consequences for testing.
I hope my comment that you replied to doesn't make it sound like I disagree with you. I don't. But I do think it is reasonable for other people to disagree with us on that point. But I also agree with dragonwriter that perhaps a more important question is the practicality of having fewer things that "use ActiveRecord", such that you can then test those things without testing the database. I think it's a pretty good idea, but I've had only limited success doing it in practice.
Thank you for this clarification. I don't know who came up with the idea that unit tests must not hit the database (it wasn't DHH). The result was that many 'mocked' unit tests merely tested their own mocks and stubs. I work on a server-side db-centric code base and many (i.e. the most important)of my unit tests involve database round trips. Speed of execution isn't a real problem in this case.
He opens with this:
> The classical definition of a unit test in TDD lore is one that doesn't touch the database. Or any other external interface, like the file system. The justification is largely one of speed. Connecting to external services like that would be too slow to get the feedback cycle you need.
No, "unit tests" in TDD -- and long before, TDD didn't change anything about the definition -- are tests that, to the extent practical, test all and only the functionality of the specific unit under test, hence the name. That's the reason why external interactions are minimized in proper unit tests (whether or not TDD is being practiced). TDD observes that such tests are generally fast, and builds the red-green-refactor cycle around that fact, but speed isn't the justification for the isolation, isolation of the functionality being tested from other functionality is the point of unit testing (which is designed not only to identify errors, but to pinpoint them.)