If you're writing unit tests, by definition, you are testing the implementation - that's the point. It seems you're referring to behavioral (or black box) tests, which are very different.
If you're writing unit tests, by definition, you are testing the implementation - that's the point. It seems you're referring to behavioral (or black box) tests, which are very different.
Black box tests are not limited to behavioral or system integration testing. you can black box at the unit level. In fact if you are doing proper TDD you will write the tests first, which help to define the interface of the class under test, make sure the test fails to ensure you are testing for something, and then finally write the implementation to make the test pass. Such an approach implies it is black box as you've defined your interface before your implementation.
Remember you are testing what it does, not how it does it.
While I tend to agree with you (I strongly prefer black-box testing over white-box testing), this is a hotly debated topic and many people feel quite strongly the opposite.
You can Google around and find many advocates for white box unit tests. Martin Fowler's article from several years ago I think does an excellent job of presenting a balanced look at both sides: http://martinfowler.com/articles/mocksArentStubs.html
> Coupling to the implementation also interferes with refactoring, since implementation changes are much more likely to break tests than with classic testing.
Fowler acknowledges two different styles of tests - state/behaviour also can be termed as classic/mockist. He doesn't really advocate one over the other. I do mock when I have to, but only when there is no other way to setup my test. It is certainly not the default. I find that taking this approach does not make my tests brittle, and makes them robust enough to handle the majority of refactoring exercises.
Of course YMMV.
We started using DI, and then had a rule that all unit tests need to be isolated. Which means mocking everything they touch.
For small methods it makes them very fragile, although the other way you end up getting a lot of intertwined tests that can wreak havoc after a lot of tests are made if you're not careful.
I've found that picking what you want to isolate seems to work the best. Our unit tests isolated everything, integration isolated any connections (i.e. DB/Services/etc) which made the tests much less fragile (and much more valuable), but made the errors harder to track down.