The recommended approach is to architect your system that you can test your code without a DB. What this means to a code perspective is using seperation of concerns. You want all of your core business logic seperated from your pages. You can do this using a MVC or MPV pattern, which if you good you can find a great deal about.
Right now there is ASP.Net MVC; however, the MVC pattern has been used in ASP.Net long before this framework existed so if your looking at enhancing an existing web forms app make sure you don't end up looking at the more recent buzz which is about ASP.Net MVC as a programing model in ASP.Net.
Now let's say you have your core logic for handling a button click isolated from page so you have a Class let's call it WidgetController. The widget controller might have a method of HandleClick() which performs your business logic.
Let's further assume that your business logic requires data access. You can again use seperation of concerns. Your business logic shouldn't care how to access the DB, all it needs is the data let another class get the data. A popular way of seperating data is by using a Depedancy Injection or Inversion of Control model (DI, IoC respectivley). Essentially what you do is define an interface for your data access, and your controller will program against the interface. You then at runtime provide the actual class to your controller via some method (Property, Constructor etc...)
What this does is it allows you to provide MOCK implementations during runtime which seperates your DB. The mocks will implement your interface and you can just new up the objects your tests will need store them in memory.