gpt4 book ai didi

unit-testing - 接收方方法相互调用时的单元测试

转载 作者:IT王子 更新时间:2023-10-29 01:38:25 26 4
gpt4 key购买 nike

假设有一个 User 包,它只包含两个简单的方法

  1. Hello 表示“你好”
  2. Say 实现用户说话的方式

原创

package user

import "fmt"

type user struct {}

func (u user) Hello() {
u.Say("Hello")
}

func (u user) Say(sentence string) {
fmt.Println(sentence)
}

但是,我们无法对 Hello 进行单元测试,因为它依赖于不可模拟的 Say

在StackOverflow和Goole上翻来覆去,我总结了两种解决问题的方法,但都不是完美的。

方法 1 - 使用 lambda 函数

用户.go

package user

import "fmt"

type user struct{}

func (u user) Hello() {
say("Hello")
}

func (u user) Say(sentence string) {
say(sentence)
}

var say = func(sentence string) {
fmt.Println(sentence)
}

用户测试.go

package user

import (
"testing"
)

func TestHello(t *testing.T) {
sayCalled := 0
sayCallArg := ""

mockSay := func(sentence string) {
sayCalled++
sayCallArg = sentence
}
say = mockSay

u := user{}
u.Hello()

if sayCalled != 1 {
t.Fatalf("not called")
}
if sayCallArg != "Hello" {
t.Fatalf("wrong arg")
}
}

方法二——使用界面

用户.go

package user

import "fmt"

type user struct {
sayer Sayer
}

func (u user) Hello() {
u.sayer.Say("Hello")
}

func (u user) Say(sentence string) {
u.sayer.Say(sentence)
}

type Sayer interface {
Say(string)
}

type sayer struct{}

func (s sayer) Say(sentence string) {
fmt.Println(sentence)
}

用户测试.go

package user

import (
"testing"
)

type mockSayer struct {
called int
calledArg string
}

func (s *mockSayer) Say(sentence string) {
s.called++
s.calledArg = sentence
}

func TestHello(t *testing.T) {
mockSayer := &mockSayer{}
u := user{sayer: mockSayer}
u.Hello()

if mockSayer.called != 1 {
t.Fatalf("not called")
}
if mockSayer.calledArg != "Hello" {
t.Fatalf("wrong arg")
}
}

我理解大多数情况,人们会建议使用方法 2,因为这就是 Go 中依赖注入(inject)的工作方式。

但是,在这个例子中,将 Say 的实现提取到另一层是很奇怪的(我认为不必要的复杂性)。

有没有更好的方案来解决这种依赖?或者您更喜欢哪种方法,为什么?

最佳答案

以上都不是。我看不出你在哪里证明 Hello 方法确实有效,“Hello\n” 确实被写入了。检查 Say 方法输出。模拟 os.Stdout。例如,

user.go:

package user

import (
"fmt"
"io"
"os"
)

type user struct{}

const hello = "Hello"

func (u user) Hello() {
u.Say(hello)
}

var stdwrite = io.Writer(os.Stdout)

func (u user) Say(sentence string) {
fmt.Fprintln(stdwrite, sentence)
}

user_test.go:

package user

import (
"bytes"
"io"
"testing"
)

func TestHello(t *testing.T) {
u := user{}

u.Hello() // for real

defer func(w io.Writer) { stdwrite = w }(stdwrite)
stdwrite = new(bytes.Buffer)

u.Hello() // for test

got := stdwrite.(*bytes.Buffer).String()
want := hello + "\n"
if got != want {
t.Errorf("want: %q got: %q", want, got)
}
}

输出:

$ go test -v
=== RUN TestHello
Hello
--- PASS: TestHello (0.00s)
PASS
ok say 0.001s

关于unit-testing - 接收方方法相互调用时的单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47362609/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com