we're in the slack of the practical language after all) Does it sound familiar to you:
1) All or nothing, I'm doing TDD!
2) I wrote a failing test, defined some interfaces, working my way with the implementation
3) 1hr later: oh wait, I change my mind, now my function accepts a callback. Let me rewrite all my tests.
4) 2hr later. Oh wait, my class got bigger, let me split it in two. Shit.. I need to split my tests now... Hm.. I know I should, but maybe, just maybe, I'll change my mind about the class 5 min later, I'll need to bring my tests back? Ok, nobody will notice, if I forget about the test file until my implementation is 100% stable.
5) Congratulations, you're done with TDD. It was a short journey.
How practical is that? No, srsly, how many teams have you seen that follow pure TDD? In 7 years I didn't see one. But I've seen a lot of TDD coaches, lol)
The fundamental problem is the mistaken idea, that you start with some nice interface or well defined expected behavior in mind, and you can write a test for it. But there is no such interface. You'll change it 100 times.
On a higher level tho, in acceptance tests, for example, or between App and Backend, there are well-defined scenarios and contracts. You write a test for the contract (let say the Rest Api is not ready, but you know the expected schema, so you don't wait for them). The contract is invariant, it stays the same. So you have something stable that you can work with, without constantly rewriting it from scratch.
I guess it's called ATDD and unlike TDD it's realistic. Writing acceptance tests for bugs, for example. It's awesome! You write an Espresso scenario that leads to a bug, It's red, you make it green, the scenario didn't change a bit during your work!