TDD Constructors Golang - sql

Even though there are a few posts on this, I haven't found one with much substance. So hopefully a few people will share opinions on this.
One thing holding me up from having a true TDD workflow is that I can't figure out a clean way to test things that have to connect to networked services like database.
For example:
type DB struct {
conn *sql.DB
}
func NewDB(URL string) (*DB, err) {
conn, err := sql.Open("postgres", URL)
if err != nil {
return nil, err
}
}
I know I could pass the sql connection to NewDB, or directly to the struct and assign it to an interface that has all the methods I need, and that would be easily testable. But somewhere, I'm going to have to connect. The only way to test this that I've been able to find is...
var sqlOpen = sql.Open
func CreateDB() *DB {
conn, err := sqlOpen("postgres", "url...")
if err != nil {
log.Fatal(err)
}
dataBase = DB{
conn: conn
}
}
Then in the test you swap out the sqlOpen function with something that returns a function with the same signature that will give an error for one test case and not give an error for another. But this feels like a hack, especially if you're doing this for several functions in the same file. Is there a better way? The codebase I'm working with has a lot of functions in packages and network connections. Because I'm struggling to test things in clean way, it's driving me away from TDD.

Typical business application has A LOT of logic in queries. We significantly decrease testing coverage and leave room for regression errors if they are not tested. So, mocking DB repositories is not the best option. Instead, we can mock database itself and test how we work with it on SQL level.
Below are sample code using DATA-DOG/go-sqlmock, but there could be other libraries that mock sql databases.
First of all, we need to inject sql connection into our code. GO sql connection is a misleading name and it is actually connections pool, not just single DB connection. That is why, it is make sense to create single *sql.DB in your composition root and reuse in your code even if you do not write tests.
Sample below shows how to mock web service.
At the beginning, we need to create new handler with injected connection:
// New creates new handler
func New(db *sql.DB) http.Handler {
return &handler{
db: db,
}
}
Handler code:
type handler struct {
db *sql.DB
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// some code that loads person name from database using id
}
Unit Test that code that mocks DB. It uses stretchr/testify for assertions :
func TestHandler(t *testing.T) {
db, sqlMock, _ := sqlmock.New()
rows := sqlmock.NewRows([]string{"name"}).AddRow("John")
// regex is used to match query
// assert that we execute SQL statement with parameter and return data
sqlMock.ExpectQuery(`select name from person where id \= \?`).WithArgs(42).WillReturnRows(rows)
defer db.Close()
sut := mypackage.New(db)
r, err := http.NewRequest(http.MethodGet, "https://example.com", nil)
require.NoError(t, err, fmt.Sprintf("Failed to create request: %v", err))
w := httptest.NewRecorder()
sut.ServeHTTP(w, r)
// make sure that all DB expectations were met
err = sqlMock.ExpectationsWereMet()
assert.NoError(t, err)
// other assertions that check DB data should be here
assert.Equal(t, http.StatusOK, w.Code)
}
Our test asserts simple SQL statement against DB. But with go-sqlmock it is possible to test all CRUD operations and database transactions.
Test above still has one weak point. We tested that our SQL statement is executed from code, but we did not test if it works against our real DB. That issue cannot be solved with unit tests. The only solution is integration test against real DB.
We are in better position now though. Out business logic is already tested in unit tests. We do not need to create lots of integration tests to cover different scenarios and parameters, instead we need to have just one test per query to verify SQL syntax and match to our DB schema.
Happy testing!

Related

Testing Go Web Scraper with Go-VCR

I'm newer to the Go language and it's resources, but have been looking around for quite some time without any luck of finding what I'm looking for. So if there is a resource out there for it, I apologize for the duplicate question and would appreciate being directed that way.
My goal is simply to build a web scraper. I'm using chromedp, which has features to focus on elements, fill in text, etc. I want to create a test environment/server to test it with during development. The main reason being that I do not want to constantly create GET requests from a website (out of common courtesy), but also be able to work offline and in addition it should also make testing a little faster. I stumbled across the go-vcr library and have been trying to get that to work, but to no avail. I can get it to record and create a .yaml, but I can't figure out how to test beyond the raw html that bounces back and gets stored in the .yaml file. My understanding is that it's possible to replicate the website and functionality of it using the library, but I'm unable to piece together how to do that.
Is what I'm trying to do possible, or is the go-vcr library (or any test/fake server for that matter) only capable of returning static data, therefore rendering anything I want to test with the web scraper not possible?
I haven't posted any code simply because I haven't pieced together much more than the examples given from the repository for the go-vcr.
I hope I was able to explain that in a way that made sense. If not I'd be happy to answer questions to clarify.
Update: Adding the example code for sake of ease. I understand how this part of it works (I think) and I can use it for testing whether or not I grabbed the proper elements of a static page, but ideally (as an example) I want to be able to fill in a text box with my program and test whether or not I successfully found the text box and filled it in without hitting the live webpage.
package vcr_test
import (
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/dnaeon/go-vcr/recorder"
)
func TestSimple(t *testing.T) {
// Start our recorder
r, err := recorder.New("fixtures/golang-org")
if err != nil {
t.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it
// Create an HTTP client and inject our transport
client := &http.Client{
Transport: r, // Inject as transport!
}
url := "http://golang.org/"
resp, err := client.Get(url)
if err != nil {
t.Fatalf("Failed to get url %s: %s", url, err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Failed to read response body: %s", err)
}
wantTitle := "<title>The Go Programming Language</title>"
bodyContent := string(body)
if !strings.Contains(bodyContent, wantTitle) {
t.Errorf("Title %s not found in response", wantTitle)
}
}

mongoskin and bulk operations? (mongodb 3.2, mongoskin 2.1.0 & 2.2.0)

I've read the various bits of literature, and I'm seeing the same problem that the questioner in
https://stackoverflow.com/a/25636911
was seeing.
My code looks like this:
coll = db.collection('foobar');
bulk = coll.initializeUnorderedBulkOp();
for entry in messages {
bulk.insert(entry);
}
bulk.execute(function (err, result) {
if (err) throw err
inserted += result.nInserted
});
bulk is an object
bulk.insert works just fine
bulk.execute is undefined
The answer in the stackoverflow question said, "only the callback flavor of db.collection() works, so I tried:
db.collection('foobar', function (err, coll) {
logger.debug "got here"
if (err) throw err
bulk = coll.initializeUnorderedBulkOp()
... same code as before
We never get to "got here" implying that the "callback flavor" of db.collection() was dropped for 3.0?
Unfortunately, my python is way better than my JS prototyping skills, so looking at the skin source code doesn't make any sense to me.
What is the right way, with mongoskin 2.1.0 and the 2.2.0 mongodb JS driver, to do a bulk operation, or is this not implemented at all anymore?
There are at least two answers:
(1) Use insert, but the array form, so you insert multiple documents with one call. Works like a charm.
(2) If you really need bulk operations, you'll need to switch from mongoskin to the native mongo interface, but just for that one call.
This kinda sucks because it's using a private interface in mongoskin, but it's also the most efficient way to stick with mongoskin:
(example in coffeescript)
// bulk write all the messages in "messages" to a collection
// and insert the server's current time in the recorded field of
// each message
// use the _native interface and wait for callback to get collection
db._native.collection collectionName, (err, collection) ->
bulk = collection.initializeUnorderedBulkOp()
for message in messages
bulk.find
_id: message._id
.upsert().updateOne
$set: message
$currentDate:
recorded: true
bulk.execute (err, result) ->
// ... error and result checking code
or (3) if you want to implement that $currentDate and not any generic bulk operation, refer to solution (1) but use the not-very-well-documented BSON object Timestamp() with no arguments:
for msg in messages:
msg.recorded = Timestamp()
db.mycollection.insert(msg)
which will do a bulk insert and set timestamp to the DB server's time at the time the record is written to the db.

How can I detect a connection failure in gorm?

I'm writing a small, simple web app in go using the gorm ORM.
Since the database can fail independently of the web application, I'd like to be able to identify errors that correspond to this case so that I can reconnect to my database without restarting the web application.
Motivating example:
Consider the following code:
var mrs MyRowStruct
db := myDB.Model(MyRowStruct{}).Where("column_name = ?", value).First(&mrs)
return &mrs, db.Error
In the event that db.Error != nil, how can I programmatically determine if the error stems from a database connection problem?
From my reading, I understand that gorm.DB does not represent a connection, so do I even have to worry about reconnecting or re-issuing a call to gorm.Open if a database connection fails?
Are there any common patterns for handling database failures in Go?
Gorm appears to swallow database driver errors and emit only it's own classification of error types (see gorm/errors.go). Connection errors do not currently appear to be reported.
Consider submitting an issue or pull request to expose the database driver error directly.
[Original]
Try inspecting the runtime type of db.Error per the advice in the gorm readme "Error Handling" section.
Assuming it's an error type returned by your database driver you can likely get a specific code that indicates connection errors. For example, if you're using PostgreSQL via the pq library then you might try something like this:
import "github.com/lib/pq"
// ...
if db.Error != nil {
pqerr, ok := err.(*pq.Error)
if ok && pqerr.Code[0:2] == "08" {
// PostgreSQL "Connection Exceptions" are class "08"
// http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html#ERRCODES-TABLE
// Do something for connection errors...
} else {
// Do something else with non-pg error or non-connection error...
}
}

Mocking a database connection

I'm trying to write some tests with PHPUnit for our various classes/methods/functions. Some of these require database connectivity. Obviously, I'd like to Mock these, so that I don't change our database(s).
Can someone point me to some code that explains how to do this? I see lots of examples of Mocking, but nothing specifically about mocking the database.
In general, you don't want to mock the database, or any other similar external dependency. It's better to wrap the database in your code with something else, and then you can mock the wrapper. Because a database might have many different ways that it can interact, whereas your code and your tests only care about one or two, your database wrapper only needs to implement those. That way mocking the wrapper should be quite simple.
You would also need some kind of integration test on the wrapper to check it's doing what it's supposed to, but there will only be a few of these tests so they won't slow your unit tests too much.
Mock of Database
I would write a wrapper around the calls to the Database in the application.
Example in Pseudo Code
CallDataBase (action, options,...) {
// Code for connectiong to DataBase
}
Then you just mock of that function just you would like any other function
CallDataBase (action, options,...) {
return true;
}
This way you can mock of the database without bothering about it being a webservice or a database connection or whatever. And you can have it return true or whatever.
Test how your system handles the database response
To take this idea one step further and make your tests even more powerful you could use some kind of test parameters or environment parameters to control what happens in the mocked off database method. Then you can successfully test how your codes handels different responses from the database.
Again in pseudo-code (assuming your database returns xml answer):
CallDataBase (action, options,...) {
if TEST_DATABASE_PARAMETER == CORRUPT_XML
return "<xml><</xmy>";
else if TEST_DATABASE_PARAMETER == TIME_OUT
return wait(5000);
else if TEST_DATABASE_PARAMETER == EMPTY_XML
return "";
else if TEST_DATABASE_PARAMETER == REALLY_LONG_XML_RESPONSE
return generate_xml_response(1000000);
}
And tests to match:
should_raise_error_on_empty_xml_response_from_database() {
TEST_DATABASE_PARAMETER = EMPTY_XML;
CallDataBase(action, option, ...);
assert_error_was_raised(EMPTY_DB_RESPONSE);
assert_written_in_log(EMPTY_DB_RESPONSE_LOG_MESSAGE);
}
...
And so on, you get the point.
Please note that all my examples are Negative test cases but this could of course be used to test Positive test cases also.
Good Luck

How do you mock your repositories?

I've use Moq to mock my repositories. However, someone recently said that they prefer to create hard-coded test implementations of their repository interfaces.
What are the pros and cons of each approach?
Edit: clarified meaning of repository with link to Fowler.
I generally see two scenarios with repositories. I ask for something, and I get it, or I ask for something, and it isn't there.
If you are mocking your repository, that means you system under test (SUT) is something that is using your repository. So you generally want to test that your SUT behaves correctly when it is given an object from the repository. And you also want to test that it handles the situation properly when you expect to get something back and don't, or aren't sure if you are going to get something back.
Hard-coded test doubles are ok if you are doing integration testing. Say, you want to save an object, and then get it back. But this is testing the interaction of two objects together, not just the behavior of the SUT. They are two different things. If you start coding fake repositories, you need unit tests for those as well, otherwise you end up basing the success and failure of your code on untested code.
That's my opinion on Mocking vs. Test Doubles.
SCNR:
"You call yourself a repository? I've seen matchboxes with more capacity!"
I assume that by "repository" you mean a DAO; if not then this answer won't apply.
Lately I've been making "in memory" "mock" (or test) implementations of my DAO, that basically operate off of data (a List, Map, etc.) passed into the mock's constructor. This way the unit test class is free to throw in whatever data it needs for the test, can change it, etc., without forcing all unit tests operating on the "in memory" DAO to be coded to use the same test data.
One plus that I see in this approach is that if I have a dozen unit tests that need to use the same DAO for their test (to inject into the class under test, for example), I don't need to remember all of the details of the test data each time (as you would if the "mock" was hardcoded) - the unit test creates the test data itself. On the downside, this means each unit test has to spend a few lines creating and wiring up it's test data; but that's a small downside to me.
A code example:
public interface UserDao {
User getUser(int userid);
User getUser(String login);
}
public class InMemoryUserDao implements UserDao {
private List users;
public InMemoryUserDao(List users) {
this.users = users;
}
public User getUser(int userid) {
for (Iterator it = users.iterator(); it.hasNext();) {
User user = (User) it.next();
if (userid == user.getId()) {
return user;
}
}
return null;
}
public User getUser(String login) {
for (Iterator it = users.iterator(); it.hasNext();) {
User user = (User) it.next();
if (login.equals(user.getLogin())) {
return user;
}
}
return null;
}
}