Проверьте ответ об ошибке в методе, который является внутренним для структуры - PullRequest
1 голос
/ 01 июня 2019

Я пишу модульные тесты и хочу написать модульный тест, который утверждает, что открытый метод в структуре (Foo.Start) правильно обрабатывает ответы об ошибках от внутреннего метода в структуре (Foo.internal).

По сути, я хочу получить тестовое покрытие в этом разделе моего кода:

if err != nil {
    return err
}

Вот пример кода и связанного с ним теста, который не работает (но работает, скажем, на Python)

# example.go

package example

import "fmt"

type FooAPI interface {
    Start() error
    internal(string) (string, error)
}

type Foo struct {
    FooAPI
}

func (foo Foo) Start() (err error) {

    data, err := foo.internal("bar")
    if err != nil {
        return err
    }

    fmt.Println(data)
    return err
}

func (foo Foo) internal(input string) (output string, err error) {
    return output, err
}
# example_test.go

package example

import (
    "testing"

    "github.com/pkg/errors"
)

type MockFoo struct {
    FooAPI
}

func (foo MockFoo) internal(input string) (output string, err error) {
    return output, errors.New("big error")
}

func TestStart(t *testing.T) {
    tdata := []struct {
        testCase        string
        expectedAnError bool
        foo             FooAPI
    }{
        {
            testCase:        "standard_case",
            expectedAnError: false,
            foo:             Foo{},
        },
        {
            testCase:        "error_case",
            expectedAnError: true,
            foo:             MockFoo{},
        },
    }
    for _, test := range tdata {
        t.Run(test.testCase, func(t *testing.T) {
            // The function under test
            test.foo.Start = Foo.Start // <= this doesn't work
            err := test.foo.Start()

            // Assertion 1
            if test.expectedAnError == false && err != nil {
                t.Error(err.Error())
            }

            // Assertion 2
            if test.expectedAnError == true && err == nil {
                t.Error("expected an error, but there was none!")
            }
        })
    }
}

Меня меньше интересует исправление конкретного примера, более того, моя цель - получить тестовое покрытие по обработке ошибок Foo.Start. Я чувствую, что есть какой-то трюк с интерфейсами или указателями, которые приведут меня сюда к финишу?

1 Ответ

1 голос
/ 01 июня 2019

Я нашел одно решение, вдохновленное https://stackoverflow.com/a/48206430/3055558

Использование структуры internal{{ your struct }} и связанного интерфейса и насмешка над этим.

# example.go

package example

import "fmt"

type internalFooAPI interface {
    internalBehavior(string) (string, error)
}

type Foo struct {
    internal internalFooAPI
}

type internalFoo struct{}

func NewFoo(internal internalFooAPI) Foo {
    return Foo{
        internal: internal,
    }
}

func (foo Foo) Start() (err error) {

    data, err := foo.internal.internalBehavior("bar")
    if err != nil {
        return err
    }

    fmt.Println(data)
    return err
}

func (foo internalFoo) internalBehavior(input string) (output string, err error) {
    return output, err
}
# example_test.go

package example

import (
    "testing"

    "github.com/pkg/errors"
)

type mockInternalFoo struct{}

type mockInternalFooWithErrors struct{}

func (foo mockInternalFoo) internalBehavior(input string) (output string, err error) {
    return output, err
}

func (foo mockInternalFooWithErrors) internalBehavior(input string) (output string, err error) {
    return output, errors.New("big error")
}

func TestStart(t *testing.T) {
    tdata := []struct {
        testCase        string
        expectedAnError bool
        foo             Foo
    }{
        {
            testCase:        "standard_case",
            expectedAnError: false,
            foo:             NewFoo(internalFoo{}),
        },
        {
            testCase:        "mock_case",
            expectedAnError: false,
            foo:             NewFoo(mockInternalFoo{}),
        },
        {
            testCase:        "error_case",
            expectedAnError: true,
            foo:             NewFoo(mockInternalFooWithErrors{}),
        },
    }
    for _, test := range tdata {
        t.Run(test.testCase, func(t *testing.T) {
            // The function under test
            err := test.foo.Start()

            // Assertion 1
            if test.expectedAnError == false && err != nil {
                t.Error(err.Error())
            }

            // Assertion 2
            if test.expectedAnError == true && err == nil {
                t.Error("expected an error, but there was none!")
            }
        })
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...