7

So I'm just getting to grips with Golang. I'm writing an application for funsies just to understand stuff and get my head around it.

I have a whole bunch of functions that will interact with a DB where I pass in *SQL.DB for the function to use. I can test those easily enough using a mocked interface from sqlmock.

No problem there.

I'm now writing the Initialisation function for the application which will initiate the DB connection which will be attached to a struct and from there passed into utility functions.

However, I am struggling to find a way to easily test that connection without having the hassle of setting up an actual database.

So I guessing that I have probably either badly structured my app, or I've missed something, potentially pretty obvious.

So here is some example code to illustrate my predicament.

util.go

package main
import (
    "log"
    "database/sql"
    "github.com/go-sql-driver/mysql"
)

func DoDBStuff(db *sql.DB) {
    rows, err := db.Query("SELECT column1, column2 FROM example")
    if err != nil {
       log.Error(err)
    }
    // do stuff with rows
}

util_test.go

package main

import (
    "testing"
    "github.com/DATA-DOG/go-sqlmock"
)

func TestDoDBStuff(t *testing.T) {
    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()

    rows := sqlmock.NewRows([]string{"col1", "col2"})
    rows.AddRow("val1", "val2")
    rows.AddRow("val3", "val4")

    mock.ExpectQuery("^SELECT column1, column2 from example$").WillReturnRows(rows)

    DoDBStuff(db)

    if err := mock.ExpectationsWereMet(); err != nil {
        t.Errorf("there were unfulfilled expectations: %s", err)
    }

}

That all works fine, I can test my DB queries.

However Now I want to test Initialising the App.

package main

import (
    "database/sql"
    "github.com/go-sql-driver/mysql"
)

type App {
    DB *sql.DB
    // some other data structures
}

func (a *App) InitApp(connectionString string) {
    a.DB = sql.Open("mysql", connectionString)
    // other init stuff
}

But as I can't pass in the SQL I don't think it can be mocked, certainly not easily. So I'm struggling a bit on how to move forward.

I am intending for this to sit behind a rest API, so on startup, the app will need to initialize before being able to process any requests.

Ideally, I'd like to be able to test the REST interface without having to set up a database, delay testing with real data until I can feed the code into a Dev environment.

So really I want to know:

Is what I'm intending possible? Is there a better approach?

If not what am I missing? Poor test design or poor code set up?

Edit:

Folling @peter's comment I just want to clarify.

I want to test the functionality of the InitDB() function but with the sql.Open call I would need to have a Database for it to connect to, If I don't then I the call would fail and I could not effectively test the function.

2
  • 1
    I'm not sure why you want to test db.Open. It's not your code. You can expect that the Go developers and authors of your database driver tested this functionality. Commented Jun 28, 2020 at 13:40
  • @Peter Good point. I've badly worded what I'm after. I want the initialise Function to do some work to set up my App ready to go. However with the sql.Open call in there then I have to have a database to connect to or it will fail. which I'm not sure how to handle that in my tests. In Python I would mock the call to sql.Open and return something that looked right. But I don't think that works in go. Commented Jun 28, 2020 at 14:04

1 Answer 1

4

There is Dockertest which creates a Docker container running whatever you want (i.e. MySQL), and you can test against that. It's designed for being able to do proper integration testing, so it should be able to do what you want (you wont need sqlmock anymore too).

Sign up to request clarification or add additional context in comments.

1 Comment

This is really useful. I did some testing using Dockertest and it works well for my use cases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.