`assert_called_once()`和`assert_called_xyz()`等价吗?

huangapple go评论73阅读模式
英文:

assert_called_once() or assert_called_xyz().... equivalent?

问题

对于在测试中断言伪造/模拟方法被调用的次数,对我来说很重要,我想知道在不使用类似于testify的东西的情况下,最好的方法是什么。在我的情况下,对伪造方法的调用是某些递归调用的结果。

假设我有一些使用表驱动测试的动物,我想断言在某些测试中实际上调用了Hello方法,但在其他测试中没有调用。在某些情况下,对于给定的测试,它应该被调用多次(在切片上迭代)。

在我的表驱动测试中,只需添加一个计数器并对其进行断言是否合适?我觉得可能有更好的方法来做这件事。

如果我确实在hello方法中添加一个计数器...在哪里处理和检查它才是合适的?在伪造方法本身中还是在测试中等等?

type fakeFarmService struct {
    abc.someFarmServiceInterface
}

func (f *fakeFarmService) Hello(ctx context.Context, in *abc.FarmRequest) (*abc.FarmResponse, error) {
    if in.GetAnimal() == Monkey {
        return &abc.HelloResponse{}, nil
    }
    return nil, errors.New("an error")
}
英文:

It is important to me to be able to assert how many times a fake / mocked method is called in my tests and I'm wondering what is the best way to do this without using something like testify. In my case, the call to the mocked method is the result of some recursive call.

Lets say I have table driven tests with various animals, I want to assert that Hello is actually called for some tests but not for others. In some cases, it should be called more than once for given test (iterating over a slice).

Is it appropriate to just add a counter and make an assertion on that in my table driven test? It seems to me like maybe there is a better way to do this.

If I do add a counter to the hello method... where is it appropriate to deal with and check this. In the fake method itself or in the test etc?

<!-- begin snippet: js hide: false console: false babel: false -->

<!-- language: lang-html -->

type fakeFarmService struct {
	abc.someFarmServiceInterface
}

func (f *fakeFarmService) Hello(ctx context.Context, in *abc.FarmRequest) (*abc.FarmResponse, error) {
	if in.GetAnimal() == Monkey {
		return &amp;abc.HelloResponse{}, nil
	}
	return nil, errors.New(&quot;an error&quot;)
}

<!-- end snippet -->

答案1

得分: 1

我过去多次使用了在结构体上使用计数器的方法,并在包级别的单元测试中进行断言。不过,这种内部断言的测试可能只适用于包级别,如果你想要测试这种内部断言。我相信这是在Go语言中做这种测试的一种被接受的方式。但是,如果你决定使用全局变量或并发运行测试,请注意正确同步对计数器的访问。

package main

import (
	"fmt"
	"sync"
	"testing"
)

type fakeable interface {
	Hello()
}

type fakeFarmService struct {
	mu      sync.Mutex
	counter int
}

func (f *fakeFarmService) Hello() {
	f.mu.Lock()
	f.counter++
	f.mu.Unlock()
}

func helloCaller(callee fakeable) {
	callee.Hello()
}

func TestCallingTheHello(t *testing.T) {
	fakeSvc := &fakeFarmService{}
	helloCaller(fakeSvc)
	helloCaller(fakeSvc)

	// 我们期望 fakeable 的 Hello 方法被调用了 2 次
	fakeSvc.mu.Lock()
	defer fakeSvc.mu.Unlock()
	if c := fakeSvc.counter; c != 2 {
		t.Errorf("unexpected call count, want 2, got %d", c)
	}
}

func main() {
	TestCallingTheHello(&testing.T{})
}

这里有一些关于Go语言高级测试的好资料:

  1. Testing Techniques by Andrew Gerrand
  2. NewStore TechTalk - Advanced Testing with Go by Mitchell Hashimoto
英文:

I've used the approach of counter on the struct and then asserting it inside the package level unit test multiple times in the past. Still, it's probably only until the level of package, when you would like to test such an internal assertions. I believe it's an accepted way of doing this in Go. Just be careful about properly synchronizing the access to the counter, if you decide to use a global variable or run the tests concurrently.

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;testing&quot;
)

type fakeable interface {
	Hello()
}

type fakeFarmService struct {
	mu      sync.Mutex
	counter int
}

func (f *fakeFarmService) Hello() {
	f.mu.Lock()
	f.counter++
	f.mu.Unlock()
}

func helloCaller(callee fakeable) {
	callee.Hello()
}

func TestCallingTheHello(t *testing.T) {
	fakeSvc := &amp;fakeFarmService{}
	helloCaller(fakeSvc)
	helloCaller(fakeSvc)

	// we expect that Hello method of fakeable was called 2 times
	fakeSvc.mu.Lock()
	defer fakeSvc.mu.Unlock()
	if c := fakeSvc.counter; c != 2 {
		t.Errorf(&quot;unexpected call count, want 2, got %d&quot;, c)
	}
}

func main() {
	TestCallingTheHello(&amp;testing.T{})
}

https://play.golang.org/p/RXKuLKIZwc (test error won't work inside the playground)

Some good material on advanced testing in Go

  1. [Testing Techniques by Andrew Gerrand][1]
  2. [NewStore TechTalk - Advanced Testing with Go by Mitchell Hashimoto][2]

[1]: https://www.youtube.com/watch?v=ndmB0bj7eyw "Testing Techniques by Andrew Gerrand"
[2]: https://www.youtube.com/watch?v=yszygk1cpEc "NewStore TechTalk - Advanced Testing with Go by Mitchell Hashimoto"

huangapple
  • 本文由 发表于 2017年9月3日 04:12:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/46017773.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定