How to go about testing queries #45
-
Hey again, I was able to get everything working for a smoke test model with the usual CRUD operations and got to work writing a test for them. The general pattern I have gone with, which could be wrong, is to pass a Note: I would like to be able to override any results to return an error as well, but have not gotten that far. Sample go code to, hopefully, illustrate my concern. // this would be the generated model
type CarModel struct {
ID string
Make string
Year int
}
// this is my http handler struct, but could be anything
type CarHandler struct {
exec bob.Executor // this type may or may not be right either
}
// Get would be similar to an HTTP Get
func (c *CarHandler) Get(ctx context.Context, id int) (*CarModel, error) {
car, err := models.FindCar(ctx, c.exec, id)
if err != nil {
// log stuff
return nil, err
}
return car, nil
}
func TestCar_GetReturnsCar(t *testing.T) {
ctx := context.Background()
// create a factory, we will use this later
factory := factory.New()
// not sure if it is possible to create some mock database executor here?
// I was kinda thinking factory had some method to return an executor
// like `factory.Executor()` in order to fake queries with a factory.
exec := bob.TestExec() // does not exist
// just build a random car model by default
factory.AddBaseCarMod(factory.CarMod.RandomizeAllColumns())
existingCar, _ := factory.NewCar().Create(ctx, exec)
// get a car from the db
c := CarHandler{exec: exec}
getCar, err := c.Get(ctx, existingCar.ID)
// require the values to match
require.Nil(t, err)
require.Equal(t, existingCar.Make, getCar.Make)
require.Equal(t, existingCar.Year, getCar.Year)
} Let me know if I missed something, I looked around the code as much as I could but couldn't find anything to solve the issue. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
func TestCar_GetReturnsCar(t *testing.T) {
ctx := context.Background()
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()
exec := bob.NewDB(db) // This is a valid bob executor
// Do the tests
} However, with factories, it becomes easier to test your code directly against a DB. You're already quite close, my preferred method is to use DATA-DOG/go-txdb to insert these entries in the DB and test against it, but run them all in a transaction and rollback after the tests finish. func init() {
// we register an sql driver named "txdb"
txdb.Register("txdb", "mysql", "root@/txdb_test")
}
func TestCar_GetReturnsCar(t *testing.T) {
db, err := sql.Open("txdb", "identifier")
if err != nil {
t.Fatalf(err)
}
defer db.Close()
exec := bob.NewDB(db) // This is a valid bob executor
// The rest of your code should work as expected and rollback after the tests finish.
// create a factory, we will use this later
factory := factory.New()
// just build a random car model by default
factory.AddBaseCarMod(factory.CarMod.RandomizeAllColumns())
existingCar, _ := factory.NewCar().Create(ctx, exec)
// get a car from the db
c := CarHandler{exec: exec}
getCar, err := c.Get(ctx, existingCar.ID)
// require the values to match
require.Nil(t, err)
require.Equal(t, existingCar.Make, getCar.Make)
require.Equal(t, existingCar.Year, getCar.Year)
} To trigger specific errors, I will say to simulate the real DB condition. For example, if the user email must be unique, use the factory to add a user with an email, and then test that your Since |
Beta Was this translation helpful? Give feedback.
bob.Executor
is just an interface which is easy to mock. Any existing package to mock adatabase/sql
connection can also be used with Bob. For example, if using DATA-DOG/go-sqlmock:However, with factories, it becomes easier to test your code directly against a DB. You're already quite close, my preferred method is to use DATA-DOG/go-txdb to insert these entr…