Testing with all the dependencies in place is still important, but it's more in the realm of integration testing as Jeffrey Faust said.
One of the most important aspect of unit testing is to make your tests trustworthy. If you don't trust that a passing test really means things are good and that a failing test really means a problem in the production code, your tests aren't nearly as useful as they can be.
In order to make your tests trustworthy, you have to do a few things, but I'm going to focus on just one for this answer. You have to make sure they are easy to run, so that all of the developers can easily run them before checking code in. "Easy to run" means that your tests run quickly and there's no extensive configuration or setup needed to make them go. Ideally, anyone should be able to check out the latest version of the code, run the tests right away, and see them pass.
Abstracting away dependencies on other things (file system, database, web services, etc.) enables you to avoid requiring configuration and makes you and other developers less susceptible to situations where you're tempted to say "Oh, tests failed because I don't have the network share set up. Oh well. I'll run them later."
If you want to test what you do with some data, your unit tests for that business logic code shouldn't care about how you get that data. Being able to test the core logic of your application without depending on supporting stuff like databases is awesome. If you're not doing it, you're missing out.
P.S. I should add that it's definitely possible to overengineer in the name of testability. Test-driving your application helps mitigate that. But in any event, poor implementations of an approach don't make the approach less valid. Anything can be misused and overdone if one doesn't keep asking "why am I doing this?" while developing.
As far as internal dependencies are concerned, things get a bit muddy. The way I like to think about it is that I want to protect my class as much as possible from changing for the wrong reasons. If I have a setup like something like this...
public class MyClass
{
private SomeClass someClass;
public MyClass()
{
someClass = new SomeClass();
}
// use someClass in some way
}
I generally don't care how SomeClass
is created. I just want to use it. If SomeClass changes and now requires parameters to the constructor... that's not my problem. I shouldn't have to change MyClass to accommodate that.
Now, that's just touching on the design part. Far as unit tests are concerned, I also want to protect myself from other classes. If I'm testing MyClass, I like knowing for a fact that there are no external dependencies, that SomeClass didn't at some point introduce a database connection or some other external link.
But an even bigger issue is that I also know that some of my methods' results rely on the output from some method on SomeClass. Without mocking/stubbing out SomeClass, I might have no way to vary that input in demand. If I'm lucky, I might be able to compose my environment inside the test in such a way that it'll trigger the right response from SomeClass, but going that way introduces complexity into my tests and makes them brittle.
Rewriting MyClass to accept an instance of SomeClass in the constructor enables me to create a fake instance of SomeClass that returns the value I want (either via a mocking framework or with a manual mock). I don't generally have to introduce an interface in this case. Whether to do so or not is in many ways a personal choice that may be dictated by your language of choice (e.g. interfaces are more likely in C#, but you definitely wouldn't need one in Ruby).