Testing code in general isn't easy. If it were, we'd have been doing it all a long time ago, and not making such a bit deal of it only in the last 10-15 years. One of the biggest difficulties has always been in determining how to test code that has been written cohesively, and well factored, and testable without breaking encapsulation. The BDD principal suggests we focus almost entirely on behavior, and in some ways seems to suggest that you don't really need to worry about the inner details to such a large degree, but this can often make things quite difficult to test if there are a lot of private methods that do "stuff" in a very hidden way, as it can increase the overall complexity of your test to deal with all the possible outcomes at a more public level.
Mocking can help to a certain extent, but again is fairly externally focused. Dependency Injection can also work quite nicely, again with mocks or test doubles, but this can also require that you expose elements either via an interface, or directly, that you might have otherwise preferred to remain hidden - this is particularly true if you wish to have a nice paranoid level of security about certain classes within your system.
For me, the jury is still out about whether to design your classes to be more easily testable. This can create problems if you find yourself needing to provide new tests while maintaining legacy code. I accept that you should be able to test absolutely everything in a system, yet I don't like the idea of exposing - even indirectly - the private internals of a class, just so that I can write a test for them.
For me, the solution has always been to take a fairly pragmatic approach, and combine a number of techniques to suit each specific situation. I use a lot of inherited test doubles to expose inner properties and behaviors for my tests. I mock everything that can be attached to my classes, and where it won't compromise the security of my classes, I'll provide a means to override or inject behaviors for the purposes of testing. I'll even consider providing a more event-driven interface if it will help improve the ability to test code
Where I find any "untestable" code, I look to see if I can refactor to make things more testable. Where you have a lot of private code doing hidden behind the scenes stuff, often you'll find new classes waiting to be broken out. These classes might be used internally, but can often be tested independently with less private behaviors, and often subsequently less layers of access and complexity. One thing I do take care to avoid however is writing production code with test code built in. It can be tempting to create "test lugs" that result in including such horrors as if testing then ...
, which indicates a testing problem not fully deconstructed and incompletely solved.
You might find it helpful to read Gerard Meszaros' xUnit Test Patterns book, which covers all of this sort of stuff in much greater detail than I can go into here. I probably don't do everything he suggests, but it does help to clarify some of the trickier test situations to deal with. At the end of the day, you want to be able to satisfy your testing requirements while still applying your preferred designs, and it helps to have a better understanding of all of the options in order to better to decide where you might need to compromise.