더 나은 통합 테스트를 위한 Go 패키지: github.com/ory/dockertest
To be clear, when I say interacting with datastores I mean where we are actually implementing the concrete repository talking directly to the datastore, not the application service type using that said repository.
옵션을 살펴보겠습니다.
Please refer to the full example code for more details.
데이터 저장소 호출 모의
사용 중인 데이터 저장소에 따라 테스트를 작성하는 다양한 방법이 있습니다. 예를 들어
database/sql
를 사용하게 된 데이터베이스 호출을 테스트하는 경우 github.com/DATA-DOG/go-sqlmock과 같은 패키지를 가져올 수 있습니다.모의 호출에 사용되는 사실상의 패키지가 없는 경우 코드에서 사용하는 구체적인 호출을 정의하는 고유한 인터페이스 유형을 정의할 수 있습니다(예: memcached calls 및
github.com/bradfitz/gomemcache
). 사용 중이면 다음과 같이 작동할 수 있습니다.// MemcacheClient defines the methods required by our Memcached implementation.
type MemcacheClient interface {
Get(string) (*memcache.Item, error)
Set(*memcache.Item) error
}
// AdapterMemcached uses a mocked client for testing.
type AdapterMemcached struct {
client MemcacheClient
}
여기서
AdapterMemcached
는 실제memcache.Client
와 필요한 메소드를 조롱하는 유형을 수신하여 다음과 같은 테스트를 성공적으로 작성할 수 있습니다.func TestAdapterMemcached(t *testing.T) {
// TODO: Test sad/unhappy-paths cases
mock := mockingtesting.FakeMemcacheClient{}
mock.GetReturns(&memcache.Item{
Value: func() []byte {
var b bytes.Buffer
_ = gob.NewEncoder(&b).Encode("value")
return b.Bytes()
}(),
}, nil)
c := mocking.NewAdapterMemcached(&mock)
if err := c.Set("key", "value"); err != nil {
t.Fatalf("expected no error, got %s", err)
}
value, err := c.Get("key")
if err != nil {
t.Fatalf("expected no error, got %s", err)
}
if value != "value" {
t.Fatalf("expected `value`, got %s", value)
}
}
통합 테스트 작성
데이터 저장소 호출을 모의하는 것은 확실히 테스트 목적으로 작동하므로 비즈니스 로직에 더 집중할 수 있지만 코드가 실제 환경에 배포될 때까지 통합 테스트가 부족하다는 단점이 있습니다.
Docker 이전에는 데이터 저장소를 조롱하는 것이 이상적인 솔루션이었지만 요즘에는 로컬 환경과 충돌하지 않고 구체적인 데이터 저장소 버전을 실행하는 로컬 컨테이너를 설정하는 것이 정말 간단합니다. 실제 데이터 저장소를 사용하고 이에 대해 테스트를 실행하는 것이 저렴합니다.
간단한 솔루션은 일반적으로 테스트 스위트를 실행하기 전에 미리 컨테이너를 실행하는 것이지만 github.com/ory/dockertest 덕분에 각 테스트 케이스 전에 컨테이너를 실제로 실행하기 쉽습니다.
ory/dockertest
Docker를 사용하여 컨테이너를 실행하고 관리합니다. 작동 방식은 API를 사용하여 배후에서 상호 작용하여 필요한 컨테이너를 적절하게 설정하는 것입니다. 이 경우에는 memcached:1.6.9-alpine
가 필요하므로 다음과 같은 기능을 구현합니다. 다음이 작동해야 합니다.func newClient(tb testing.TB) *memcache.Client {
pool, err := dockertest.NewPool("")
if err != nil {
tb.Fatalf("Could not instantiate docker pool: %s", err)
}
pool.MaxWait = 2 * time.Second
// 1. Define configuration options for the container to run.
resource, err := pool.RunWithOptions(&dockertest.RunOptions{
Repository: "memcached",
Tag: "1.6.6-alpine",
}, func(config *docker.HostConfig) {
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{
Name: "no",
}
})
if err != nil {
tb.Fatalf("Could not run container: %s", err)
}
addr := fmt.Sprintf("%s:11211", resource.Container.NetworkSettings.IPAddress)
if runtime.GOOS == "darwin" { // XXX: network layer is different on Mac
addr = net.JoinHostPort(resource.GetBoundIP("11211/tcp"), resource.GetPort("11211/tcp"))
}
// 2. Wait until the container is available and instantiate the actual client
// the value set above in `pool.MaxWait` determines how long it should wait.
if err := pool.Retry(func() error {
var ss memcache.ServerList
if err := ss.SetServers(addr); err != nil {
return err
}
return memcache.NewFromSelector(&ss).Ping()
}); err != nil {
tb.Fatalf("Could not connect to memcached: %s", err)
}
tb.Cleanup(func() {
// 3. Get rid of the containers previously launched.
if err := pool.Purge(resource); err != nil {
tb.Fatalf("Could not purge container: %v", err)
}
})
return memcache.New(addr)
}
이것은 테스트 스위트 또는 테스트 케이스당 새로운 컨테이너를 실행합니다(테스트 실행 계획에 따라 다름). 초기화를 통해 테스트 중에 사용할 memcached 도커 컨테이너를 실제로 실행할 수 있으며, 필요한 유형을 다룹니다.
memcached.Client
뿐만 아니라:func TestConcreteMemcached(t *testing.T) {
// TODO: Test sad/unhappy-paths cases
client := newClient(t)
c := mocking.NewConcreteMemcached(client)
if err := c.Set("concrete-key", "value"); err != nil {
t.Fatalf("expected no error, got %s", err)
}
value, err := c.Get("concrete-key")
if err != nil {
t.Fatalf("expected no error, got %s", err)
}
if value != "value" {
t.Fatalf("expected `value`, got %s", value)
}
}
마지막 생각들
Go에서 데이터 저장소로 작업할 때 github.com/ory/dockertest을 사용하지 않을 변명의 여지가 없습니다.
ory/dockertest
통합 테스트를 단순화하고 테스트를 실행할 때 필요한 종속성을 줄입니다. 이러한 경우에는 Docker만 필요하기 때문입니다.그러나 우리는 조심해야 하고 그것을 남용하지 않아야 합니다. 비록 우리가 말 그대로 하위 테스트당 하나의 컨테이너를 생성할 수 있는 옵션이 있지만 결국에는 최선의 아이디어가 아닐 수 있다는 점을 명심해야 합니다. 테스트 테스트 기간을 측정하여 제품군에 필요한 최상의 컨테이너 수를 결정해야 합니다. 시작하는 것이 좋습니다. 각 테스트 사례에 대해 하나씩 사용하고 격리에 따라 하위 테스트 수와 일치하도록 해당 값을 늘릴 수 있습니다. .
결국
ory/dockertest
은 필수, 적극 권장합니다.
Reference
이 문제에 관하여(더 나은 통합 테스트를 위한 Go 패키지: github.com/ory/dockertest), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/mariocarrion/go-package-for-better-integration-tests-github-com-ory-dockertest-290m텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)