We use a Developer Machine that builds and runs everything in the project for each developer that is part of the team. So all developers have a working (complete) system on their box. We have a build server that either does nightly builds or continues integration. The build server runs all Unit Tests - always. We have our source control (SVN or TFS) on a seperate server as well (shared between projects).
Then we have a Developement Environment. Usually just a simplification of the deployment of the solution (so no load balancing and stuff). This is the first real distributed integration of the solution. Its also a playground for the development team to try out things.
We have a Test Environment. Usually similar deployment to the Develepment Environment. This is the place that is used by the Test Team to run their tests. Any defects are reported to a central repository (either a SharePoint List or TFS Work-Item) and fixed by the development team.
Then there is an acceptance environment that matches the production environment as closely as possible. This environment is used for pre-production tests and go/no-go decisions by the customer (acceptance of the new version).
And there is the Production Environment which is never under the control of the development team (Development and Test usually are) and runs the final bits.
Each release/version is packaged and moved through the environments, never changing anything to the package. So if the test team finds bugs, the developers fix them and make a new package that contains these fixes and start at the Development Environment.
So its cheapest to catch bugs early and that is why Unit Testing is important but also having a good test team ;-)
Most of these environments are build using virtual servers. Database servers (SQL-Server) /clusters as well as BizTalk (messaging) are usually not virtual in a production environment.
Hope it helps.