Я пишу пакет Go, который обрабатывает взаимодействие с BoltDB как часть более крупного проекта. У меня есть 2 метода взаимодействия с БД.
func Lookup(path string) (string, bool) {}
func RegisterUrl(path, url string) error {}
Lookup делает запрос к базе данных для получения соответствующего URL-адреса, тогда как RegisterUrl записывает пару ключ-значение path: url в базу данных.
Я хотел бы попросить обзор моей реализации и несколько советов по реализации модульных тестов.
Модульное тестирование
Я включил скелет для модульных тестов, которые я хотел бы иметь для двух вышеупомянутых функций. Однако мне сложно понять, как лучше всего их реализовать.
- Я бы не хотел тестировать методы, использующие базу данных / ведро «prod», вместо этого я бы предпочел поменять местами prod DB для тестирования DB в
database_test.go
файл. - Я подумал о том, чтобы сделать общедоступные переменные dbName и bucketName в
database.go
а затем измените их в файле _test для test db, но похоже, что я нарушу инкапсуляцию. - Я также рассматривал возможность передачи тестовой базы данных / ведра в функции в качестве функциональных опций, но похоже, что это усложнит код, и я не уверен, что это лучший подход.
Буду рад услышать ваш совет.
database.go
// Package database handles communication with BoltDB.
package database
import (
"log"
"time"
"github.com/boltdb/bolt"
)
var dbOptions *bolt.Options = &bolt.Options{
Timeout: 1 * time.Second,
}
const (
dbName = "urls.db"
bucketName = "UrlFromPath"
)
func init() {
// Make sure that the database exists.
db, err := bolt.Open(dbName, 0600, dbOptions)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Make sure that UrlFromPath bucket exists.
err = db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(bucketName))
if err != nil {
return err
}
return nil
})
if err != nil {
log.Fatal(err)
}
}
// Lookup checks if `path` key exists in database and returns related `url` value if found. If not
// found second return value `ok` is set to false.
func Lookup(path string) (url string, ok bool) { // TODO: return
// Open connection to DB.
db, err := bolt.Open(dbName, 0600, dbOptions)
if err != nil {
log.Fatalf("Cannot connect to DB: %s", err)
return "", false
}
defer db.Close()
// Retreive url from DB.
var url_bytes []byte
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
url_bytes = b.Get([]byte(path))
return nil
})
if err != nil {
return "", false
}
if url_bytes != nil {
return string(url_bytes), true
} else {
return "", false
}
}
// RegisterUrl saves provided key:value (path:url) pair to database.
func RegisterUrl(path, url string) error {
// Open connection to DB.
db, err := bolt.Open(dbName, 0600, dbOptions)
if err != nil {
return err
}
defer db.Close()
// Save path and url.
err = db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
err := b.Put([]byte(path), []byte(url))
return err
})
if err != nil {
return err
}
log.Printf("Database: %s, %s registered.", path, url)
return nil
}
database_test.go
package database
import "testing"
func setup() {
// Init test db.
// Init test bucket.
}
func cleanup() {
// Remove test db.
}
func TestLookup(t *testing.T) {
// T1. Path exists in db. Correct url is retrieved.
// T2. Path doesn't exist in db. false is returned.
}
func TestRegisterUrl(t *testing.T) {
// T1. Add path:url to db. Correct path:url pair has been added to db.
}
```