README ¶
upper/db Test Adapter
This is an upper/db database adapter used for unit tests.
Usage
testadapter
can be imported with import "gitlab.com/zyrthofar/upperdb-test-adapter/pkg/testadapter"
.
testadapter.Session
follows the db.Session
interface. When a package uses a db.Session
dependency, testadapter
can be used during unit tests instead of connecting to a real database, which would actually make them integration tests. It is then configured with specific expectations so that the outcome of tests are predictable and reproductable.
How expectations are defined is similar to the actual database functions. For example:
sess := testadapter.NewSession(t)
sess.Collection("users").
Find(db.Cond{"id": 1234}).
Where(db.Cond{"disabled": false}).(*testadapter.Result).
ExpectOneArgs(&User{}, &User{ID: 1234, Name: "John"}, nil)
Alternatively, the previous expectation's expected and returned values can be grouped together in a ResultOneExpectation
, which is useful in test suites. A more complete example follows, in which the last test (a database failure) cannot usually be tested during integration or end-to-end tests:
func TestFindByID(t *testing.T) {
tests := map[string]struct {
userID int
dbResultOneExpt *testadapter.ResultOneExpectation
expectedErrorMessage string
}{
"whenUserIsValid": {
userID: 1234,
dbResultOneExpt: &testadapter.ResultOneExpectation{
ExpectedItem: &User{},
ReturnedItem: &User{ID: 1234, Name: "John"},
ReturnedError: nil,
},
expectedUser: &User{ID: 1234, Name: "John"},
expectedErrorMessage: nil,
},
"whenUserIsNotFound": {
userID: -1,
dbResultOneExpt: &testadapter.ResultOneExpectation{
ExpectedItem: &User{},
ReturnedItem: nil,
ReturnedError: ErrUserNotFound,
},
expectedUser: nil,
expectedErrorMessage: "error retrieving user: user not found",
},
"whenDatabaseFailedToRetrieveUser": {
userID: 1234,
dbResultOneExpt: &testadapter.ResultOneExpectation{
ExpectedItem: &User{},
ReturnedItem: nil,
ReturnedError: ErrDatabaseUnreachable,
},
expectedUser: nil,
expectedErrorMessage: "error retrieving user: database unreachable",
},
}
for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
sess := testadapter.NewSession(t)
sess.Collection("users").
Find(db.Cond{"id": tt.userID}).
Where(db.Cond{"disabled": false}).(*testadapter.Result).
ExpectOne(tt.dbResultOneExpt)
user, err := Users(sess).FindByID(tt.userID)
if err != nil {
if tt.expectedErrorMessage != err.Error() {
t.Fatalf(
"expected error message to be `%s`, but was `%s`",
tt.expectedErrorMessage,
err.Error(),
)
}
return
}
if tt.expectedUser != user {
t.Fatalf(
"expected user to be `%v`, but was `%v`",
tt.expectedUser,
user,
)
}
})
}
}
Limitations
Not all features derived from db.Session
are currently implemented. The following sections list the methods that are available. Information about their usage can be found in their respective files.
Session
session.Get
session.Save
session.Delete
Collection
session.Collection.Count
session.Collection.Exists
session.Collection.Insert
session.Collection.InsertReturning
session.Collection.UpdateReturning
session.Collection.Truncate
Result
session.Collection.Find.*.Count
session.Collection.Find.*.Exists
session.Collection.Find.*.All
session.Collection.Find.*.One
session.Collection.Find.*.Update
session.Collection.Find.*.Delete
Selector
session.SQL.Select|SelectFrom.*.All
session.SQL.Select|SelectFrom.*.One