다음과 같은 테이블 기반 테스트 케이스가 있습니다.
func CountWords(s string) map[string]int
func TestCountWords(t *testing.T) {
var tests = []struct {
input string
want map[string]int
}{
{"foo", map[string]int{"foo":1}},
{"foo bar foo", map[string]int{"foo":2,"bar":1}},
}
for i, c := range tests {
got := CountWords(c.input)
// TODO test whether c.want == got
}
}
길이가 동일한 지 확인하고 모든 키-값 쌍이 동일한 지 확인하는 루프를 작성할 수 있습니다. 그러나 다른 유형의지도에 사용하려면이 수표를 다시 작성해야합니다 (예 🙂 map[string]string
.
결국 내가 한 것은 맵을 문자열로 변환하고 문자열을 비교하는 것입니다.
func checkAsStrings(a,b interface{}) bool {
return fmt.Sprintf("%v", a) != fmt.Sprintf("%v", b)
}
//...
if checkAsStrings(got, c.want) {
t.Errorf("Case #%v: Wanted: %v, got: %v", i, c.want, got)
}
이것은 동등한 맵의 문자열 표현이 동일하다고 가정합니다.이 경우에는 사실 인 것처럼 보입니다 (키가 동일하면 동일한 값으로 해시되므로 순서가 동일합니다). 이 작업을 수행하는 더 좋은 방법이 있습니까? 테이블 기반 테스트에서 두 맵을 비교하는 관용적 방법은 무엇입니까?
답변
Go 라이브러리는 이미 당신을 덮었습니다. 이 작업을 수행:
import "reflect"
// m1 and m2 are the maps we want to compare
eq := reflect.DeepEqual(m1, m2)
if eq {
fmt.Println("They're equal.")
} else {
fmt.Println("They're unequal.")
}
당신이 보면 소스 코드 에 대한 reflect.DeepEqual
의 Map
경우 그들이 전에 마지막으로 그들이 (키의 동일한 세트가 있는지 확인 같은 길이가 있다면, 당신은 다음 수표, 모두 매핑하고있는 경우에 최초로 확인이 전무 것을 볼 수 있습니다 값) 쌍.
reflect.DeepEqual
인터페이스 유형을 취하기 때문에 유효한 모든지도 ( map[string]bool, map[struct{}]interface{}
등)에서 작동합니다. 비맵 값에서도 작동하므로 전달하는 것이 실제로 두 개의 맵이라는 점에 유의하십시오. 두 개의 정수를 전달하면 같은지 여부를 기꺼이 알려줍니다.
답변
테이블 기반 테스트에서 두 맵을 비교하는 관용적 방법은 무엇입니까?
당신은 go-test/deep
도울 프로젝트 가 있습니다.
하지만 기본적으로 Go 1.12 (2019 년 2 월)를 사용하면이 작업이 더 쉬워 질 것입니다 . 출시 노트를 참조하세요 .
fmt.Sprint(map1) == fmt.Sprint(map2)
fmt
이제 맵은 테스트를 쉽게하기 위해 키 정렬 순서로 인쇄됩니다 .
주문 규칙은 다음과 같습니다.
- 적용 가능한 경우 nil은 낮음을 비교합니다.
- 정수, 부동 소수점 및 문자열 순서
<
- NaN은 비 NaN 수레보다 적은 수를 비교합니다.
bool
false
전에 비교true
- 복잡함은 실제와 가상의 비교
- 컴퓨터 주소로 포인터 비교
- 컴퓨터 주소로 채널 값 비교
- 구조체는 각 필드를 차례로 비교합니다.
- 배열은 각 요소를 차례로 비교합니다.
- 인터페이스 값은 먼저
reflect.Type
구체적인 유형 을 설명하여 비교 한 다음 이전 규칙에서 설명한대로 구체적인 값으로 비교 합니다.지도를 인쇄 할 때 NaN과 같은 비 반사 키 값은 이전에로 표시되었습니다
<nil>
. 이 릴리스부터 올바른 값이 인쇄됩니다.
출처 :
golang/go
문제 21095 ,- 트윗 (해당 패치의 원래 아이디어 : ᴊᴀᴍᴇꜱ ᴊᴜꜱᴛ ᴊᴀᴍᴇꜱ (
purpleidea
) - CL 142737 :
CL은 다음을 추가합니다. ( CL은 “변경 목록”을 나타냄)
이를 위해 루트에 패키지를
internal/fmtsort
추가 합니다.이 패키지는 유형에 관계없이 맵 키를 정렬하는 일반적인 메커니즘을 구현합니다.이것은 약간 지저분하고 느릴 수 있지만 맵의 형식화 된 인쇄는 결코 빠르지 않았으며 이미 항상 반사 중심입니다.
새 패키지는 내부에 있습니다. 모든 사람이 이것을 사용하여 물건을 분류하는 것을 원하지 않기 때문입니다. 일반적이지 않고 느리고 맵 키가 될 수있는 유형의 하위 집합에만 적합합니다.
또한 text/template
이미이 메커니즘의 약한 버전이있는 의 패키지를 사용하십시오 .
당신은에서 사용 된 것을 볼 수 있습니다 src/fmt/print.go#printValue(): case reflect.Map:
답변
이것은 내가 할 일입니다 (테스트되지 않은 코드).
func eq(a, b map[string]int) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
if w, ok := b[k]; !ok || v != w {
return false
}
}
return true
}
답변
면책 조항 : map[string]int
질문의 제목 인 Go에서지도의 동등성 테스트와 관련이 없지만 관련이 있음
당신이 포인터 타입의지도가있는 경우 (같은 map[*string]int
), 당신은 할 수 없습니다 reflect.DeepEqual를 사용하려면 false를 반환 때문입니다.
마지막으로, 키가 time.Time과 같이 내 보내지 않은 포인터를 포함하는 유형 인 경우 이러한지도에서 reflect.DeepEqual 도 false를 반환 할 수 있습니다 .
답변
github.com/google/go-cmp/cmp 의 “Diff”방법을 사용합니다 .
암호:
// Let got be the hypothetical value obtained from some logic under test
// and want be the expected golden data.
got, want := MakeGatewayInfo()
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("MakeGatewayInfo() mismatch (-want +got):\n%s", diff)
}
산출:
MakeGatewayInfo() mismatch (-want +got):
cmp_test.Gateway{
SSID: "CoffeeShopWiFi",
- IPAddress: s"192.168.0.2",
+ IPAddress: s"192.168.0.1",
NetMask: net.IPMask{0xff, 0xff, 0x00, 0x00},
Clients: []cmp_test.Client{
... // 2 identical elements
{Hostname: "macchiato", IPAddress: s"192.168.0.153", LastSeen: s"2009-11-10 23:39:43 +0000 UTC"},
{Hostname: "espresso", IPAddress: s"192.168.0.121"},
{
Hostname: "latte",
- IPAddress: s"192.168.0.221",
+ IPAddress: s"192.168.0.219",
LastSeen: s"2009-11-10 23:00:23 +0000 UTC",
},
+ {
+ Hostname: "americano",
+ IPAddress: s"192.168.0.188",
+ LastSeen: s"2009-11-10 23:03:05 +0000 UTC",
+ },
},
}
답변
대신 cmp ( https://github.com/google/go-cmp )를 사용 하세요 .
if !cmp.Equal(src, expectedSearchSource) {
t.Errorf("Wrong object received, got=%s", cmp.Diff(expectedSearchSource, src))
}
예상 출력의 맵 “순서”가 함수가 반환하는 것과 다를 때 여전히 실패합니다. 그러나 cmp
여전히 불일치가 어디에 있는지 지적 할 수 있습니다.
참고로이 트윗을 찾았습니다.
https://twitter.com/francesc/status/885630175668346880?lang=en
“테스트에서 reflect.DeepEqual을 사용하는 것은 종종 나쁜 생각입니다. 그래서 우리는 http://github.com/google/go-cmp를 오픈 소스로 제공합니다. “-Joe Tsai
답변
가장 간단한 방법 :
assert.InDeltaMapValues(t, got, want, 0.0, "Word count wrong. Got %v, want %v", got, want)
예:
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestCountWords(t *testing.T) {
got := CountWords("hola hola que tal")
want := map[string]int{
"hola": 2,
"que": 1,
"tal": 1,
}
assert.InDeltaMapValues(t, got, want, 0.0, "Word count wrong. Got %v, want %v", got, want)
}