Drone is in fact written in Go and since we're using the db/sql package I can share how we do our database testing.
We have a package where we define all of our database interactions using interfaces:
type ProjectService interface {
// Create a new Project.
Create(proj *Project) (bool, error)
// Update an existing Project in the database.
Update(proj *Project) (bool, error)
...
}
We then have an implementation of the interface that works with a postgres driver (all the select statements, prepared statements, etc). We have unit tests for each method that rely on a local database to verify all our sql syntax is correct and that we are mapping all of our columns correctly. These tests get run on our CI server every time we make a commit. Each build is executed in a fresh VM with an untainted postgres install (like Jason mentioned) which makes the unit testing more repeatable.
We also have a mock implementation of the interface so that we can run tests without a database all together:
type MockProjectService struct {
OnCreate func(proj *Project) (bool, error)
OnUpdate func(proj *Project) (bool, error)
...
}
func (t *MockProjectService) Create(proj *Project) (bool, error) {
return t.OnCreate(proj)
}
func (t *MockProjectService) Update(proj *Project) (bool, error) {
return t.OnUpdate(proj)
}
When unit testing our http.Handlers we use the mock implementation. This allows us to create very specific success and failure scenarios without having to worry about the database running locally and being populated with an exact dataset (which is fragile and can have cascading effects if a single unit test fails).