Насмешливые методы - PullRequest
       5

Насмешливые методы

0 голосов
/ 13 сентября 2018

Я пишу небольшую POC на ходу на работу, но я не могу понять методы насмешки.это то, что у меня есть ...

connect.go

package db

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "strings"

    _ "github.com/lib/pq"
)

type config map[string]interface{}

type DbConn struct {
    db db
}

type db interface {
    getConnectionStringFromConfig(file string) (connStr string, err error)
}

func NewDbConn(d db) *DbConn {
    return &DbConn{db: d}
}

func getConnectionStringFromConfig(file string) (connStr string, err error) {
    var c config
    var bt []byte
    if bt, err = ioutil.ReadFile(file); err != nil {
        fmt.Printf("Error Reading config file: %v", err)
        return
    }
    fmt.Println("Finish reading file. Going to construct a connection string")
    if err = json.Unmarshal(bt, &c); err != nil {
        fmt.Printf("Error unmarshalling config file: %v", err)
        return
    }
    connStr = strings.TrimLeft(getConfigAsString(c), " ")
    return
}

func getConfigAsString(c config) (connStr string) {
    for k, v := range c {
        connStr += strings.Join([]string{" " + k, v.(string)}, "=")
    }
    return
}

// Connect database connection
func (dbConn DbConn) Connect() (conn *sql.DB, err error) {
    fmt.Println("Starting database connection...")
    connStr, err := getConnectionStringFromConfig("path/to/conf.json")
    if err != nil {
        return
    }
    conn, err = sql.Open("some_driver", connStr)
    return
}

connect_test.go

package db

import (
    "errors"
    "testing"
)

type dbConnMock struct {
    db dbMock
}

type dbMock interface {
    getConnectionStringFromConfig(file string) (connStr string, err error)
}

func (dbm dbConnMock) getConnectionStringFromConfig(file string) (connStr string, err error) {
    return "", errors.New("123")
}

// should not throw error when trying to open db connection
func TestDatabaseConnection(t *testing.T) {
    dbCon := &DbConn{}
    _, err := dbCon.Connect()
    if err != nil {
        t.Errorf("test failed. \n %d", err)
    }
}

func TestDatabaseConnectionFail(t *testing.T) {
    var dm dbMock
    dbCon := NewDbConn(dm)
    _, err := dbCon.Connect()
    if err == nil {
        t.Errorf("test failed. %d", err)
    }
}

Как видите, это простая логика подключения к базе данных, которую я тестирую и проверяю с помощью интерфейса.Я хочу охватить 100% кода, поэтому мне приходится издеваться над определенными методами.Приведенный выше код, хотя и работает, второй тест не пройден, возможно, из-за того, что я что-то упустил в своих попытках издеваться над ним.Пожалуйста, помогите ..

1 Ответ

0 голосов
/ 13 сентября 2018

Есть несколько вещей, которые вы можете сделать.


Простой способ

Если вы хотите сохранить простоту, то вы можете сделать так, чтобы ваша фиктивная структура имела поля для того, что она должна возвращать, и в каждом тестовом случае вы устанавливаете эти поля равными тому, что ваш макет должен возвращать для этого тестового примера.

Таким образом, вы можете заставить свой макет преуспеть или потерпеть неудачу различными способами.

Кроме того, вам не нужен интерфейс dbMock, поскольку dbConnMock реализует интерфейс db, и это все, что вам нужно.

Вот как может выглядеть ваша насмешка:

type dbConnMock struct {
    FileCalled string

    connStr string
    err error
}

func (dbm dbConnMock) getConnectionStringFromConfig(file string) (connStr string, err error) {
    dbm.FileCalled = file
    return dbm.connStr, dbm.err
}

Теперь вы можете проверить, что ваш метод был вызван с ожидаемым аргументом, используя FileCalled, и вы можете настроить его на поведение , которое вы хотели бы смоделировать .

Если вы также хотите убедиться, что ваш метод вызывается только один раз, вы также можете добавить счетчик, чтобы увидеть, сколько раз он был вызван, например.


Использование библиотеки-макета Если вы не хотите беспокоиться о написании этой логики, несколько библиотек могут сделать это за вас, например, testify / mock . Вот пример того, как простой макет будет работать с использованием testify/mock: type dbMock struct { mock.Mock } func (m *dbMock) getConnectionStringFromConfig(file string) (string, error) { args := m.Called(file) return args.String(0), args.Error(1) } func TestSomething(t *testing.T) { tests := []struct { description string connStr string err error expectedFileName string // add expected outputs and inputs of your tested function }{ { description: "passing test", connStr: "valid connection string", err: nil, expectedFileName: "valid.json", }, { description: "invalid file", connStr: "", err: errors.New("invalid file"), expectedFileName: "invalid.json", }, } for _, test := range tests { t.Run(test.description, func(t *testing.T) { dbMock := &dbConnectionMock{} dbMock. On("getConnectionStringFromConfig", test.expectedFileName). Return(test.connStr, test.err). Once() thing := &Something{ db: dbMock, } output, err := thing.doSomething() // assert that output and err are expected dbMock.AssertExpectations(t) // this will make sure that your mock is only used as expected in your test, depending on your `On` calls }) } } Этот код гарантирует, что ваш метод вызывается один раз и с конкретными аргументами, и заставит его возвращать то, что указано в вашем тестовом примере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...