Yunseok's Dev Blog

배운 것을 적는 블로그입니다.

Gomega Matchers

Asserting Equivalence

Equal(expected interface{})

Expect(ACTUAL).To(Equal(EXPECTED))
  • 내부적으로 reflect.DeepEqual을 사용해서 ACTUALEXPECTED를 비교합니다.
  • maps, slices, arrays, struct들을 재귀적으로 검사합니다.
  • type도 strict 하게 검사하기 때문에 비교하는 대상의 타입이 같아야 합니다.
  • 다른 타입과의 비교를 할 때는 BeEquivalentTo를 사용해야 합니다.
  • 둘다 nil이면 에러가 발생합니다.

BeEquivalentTo(expected interface{})

Expect(ACTUAL).To(BeEquivalentTo(EXPECTED))
  • Equal과 동일하게 내부적으로 refelect.DeepEqual을 사용해서 ACTUALEXPECTED를 비교합니다.
  • 하지만 Equal과 다르게 ACTUAL의 타입을 EXPECTED의 타입으로 변경한 후 비교를 합니다.
  • 둘다 nil이면 에러가 발생합니다.
  • 숫자를 사용해서 비교를 할때는 사용하면 안됩니다.
Expect(5.1).Should(BeEquivalentTo(5))
Expect(5).ShouldNot(BeEquivalentTo(5.1))
  • 위의 결과는 둘다 통과하게 됩니다. 이런 경우에는 BeNumerically()을 사용해야 합니다.

BeIdenticalTo(expected interface{})

Expect(ACTUAL).To(BeIdenticalTo(EXPECTED))
  • Equal과 동일하게 내부적으로 refelect.DeepEqual을 사용해서 ACTUALEXPECTED를 비교합니다.
  • 하지만 ==을 사용해서 을 비교합니다.
  • 비교한 두 대상이 포인터라면 포인터가 가리키고 있는 메모리의 주소가 같은지 비교합니다.
  • 둘다 nil이면 에러가 발생합니다.

BeAssignableToTypeOf(expected interface)

Expect(ACTUAL).To(BeAssignableToTypeOf(EXPECTED))
  • ACTUALEXPECTED와 같은 타입으로 할당할 수 있는지 비교합니다.
  • 둘다 nil이면 에러가 발생합니다.

Asserting Presence

BeNil()

Expect(ACTUAL).To(BeNil())
  • ACTUAL이 nil인지 검사합니다.

BeZeroBeIdenticalTo(EXPECTED)

Expect(ACTUAL).To(BeZero())
  • ACTUAL이 zero value인지 혹은 nil인지 검사합니다.

Asserting Truthiness

BeTrue()

Expect(ACTUAL).To(BeTrue())
  • ACTUALtrue인지 검사합니다.
  • ACTUALbool타입이어야 합니다.

BeFalse()

Expect(ACTUAL).To(BeFalse())
  • ACTUALfalse인지 검사합니다.
  • ACTUALbool타입이어야 합니다.

Asserting on Errors

HaveOccurred()

err := SomethingThatMightFail()
Expect(err).ToNot(HaveOccurred())
  • 에러가 있으면 통과합니다.

Succeed()

Expect(FUNCTION()).ToNot(HaveOccurred())
  • 함수가 nil을 return하면 통과합니다.
  • error를 첫 번째 인자로 return하거나 error만 return하는 함수에 사용해야 합니다.

MatchError(expected interface{})

Expect(ACTUAL).To(MatchError(EXPECTED))
  • EXPECTED가 문자열일 경우 ACTUAL.Error()과 비교를 합니다.
  • EXPECTEDerror일 경우 refelect.DeepEqaul로 비교를 합니다.

Working with Channels

BeClosed()

Expect(ACTUAL).To(BeClosed())
  • ACTUAL이 닫힌 채널이면 통과합니다.
  • 만약 채널이 아니면 에러가 발생합니다.
  • Gomega가 채널이 닫혔는지 확인하기 위해 채널에서 read를 시도합니다. 따라서 이후에 또 이 채널을 통해 뭔가를 검사한다면 이점을 명심해야 합니다.
  • 만약 buffered 채널이 닫혔는지 테스트를 한다면 만드시 채널의 모든 값을 read해야 합니다.

Receive()

Expect(ACTUAL).To(Receive(<optionalPointer>))
  • 수신 할 메시지가 있으면 통과합니다.
  • ACTUAL은 반드시 채널이어야 하고 send-only 채널이면 안됩니다.
  • Receive는 즉시 실행되며 블락킹하지 않습니다.
  • 채널 c에 데이터가 없다면 Expect(c).To(Receive())는 실패하고 Expect(c).NotTo(Receive())는 통과합니다.
  • 채널 c에 읽을 데이터가 있다면 Expect(c).To(Receive())는 통과하고 Expect(c).NotTo(Receive())는 실패합니다.
  • 채널 c가 닫혔다면 Expect(c).To(Receive())는 실패하고 Expect(c).NotTo(Receive())는 통과합니다.
go func() {
    time.Sleep(100 * time.Millisecond)
    c <- true
}()
  • 위와같은 go routine이 있을 때 c는 어떤 아무 값이나 받기 때문에 다음은 통과를 하게 됩니다.
Eventually(c).To(Receive())
  • c가 아무런 값을 받지 못한다면 타임아웃이 발생합니다.
  • go-routine이 채널에 값을 write하지 않을 때를 테스트하고 싶을 때는 다음과같이 작성할 수 있습니다.
Consistently(c).NotTo(Receive())
  • 또한 채널에서 받아온 값을 추가적으로 검사할 수 있습니다.
Eventually(c).To(Receive(Equal("foo")))
  • Eventually는 주기적으로 채널 c를 폴링합니다. 건네받은 Matcher를 채우지 않는 채널에 오브젝트가 존재하는 경우, Matcher를 채우는 오브젝트가 수신 될 때까지 오브젝트는 꺼내져 삭제됩니다.
  • 또한 채널을 통해 전송 된 객체를 잡아야하는 경우가 있습니다 (예 : 객체에 대해 여러 가지 어설 션을 수행하는 경우). 이렇게하려면 적절한 형식의 변수에 대한 포인터를 전달하여 채널에 전달 된 값에 대해 Receive matcher에 요청할 수 있습니다.
var receivedBagel Bagel
Eventually(bagelChan).To(Receive(&receivedBagel)). 
Expect(receivedBagel.Contents()).To(ContainElement("cream cheese"))
Expect(receivedBagel.Kind()).To(Equal("sesame"))
  • 물론 이것은 receivedBagel : = <-bagelChan으로 작성되었을 수 있습니다. 그러나 Receive를 사용하면 채널에 아무 것도 나오지 않아도 테스트 스위트를 매달 기는 것을 쉽게 피할 수 있습니다. 포인터는 채널 요소 유형에서 유형을 할당 할 수있는 변수를 가리킬 수 있으며 채널 유형이 인터페이스이고 기본 유형을 포인터에 할당 할 수있는 경우 변수를 가리킬 수 있습니다.

BeSent(value interface{})

Expect(ACTUAL).To(BeSent(VALUE))
  • VALUE를 channel ACTUAL로 블락킹 없이 전송합니다. 성공하면 테스트가 통과합니다.
  • ACTUAL
    • 반드시 channel이어야 합니다.
    • receive-only 채널이면 안됩니다.
    • 닫혀있지 않아야합니다.
  • BeSent는 블락킹하지 않습니다.
    • 채널이 받을 준비가 안되어있다면 실패합니다.
    • 채널이 받을 준비가 되어 있다면 성공하비다.
    • 채널이 닫혔다면 To(BeSent("foo"))NotTo(BeSent("foot"))둘다 실패합니다.

Working with files

BeAnExistingFile

Expect(ACTUAL).To(BeAnExistingFile())
  • 파일이 ACTUAL위치에 있으면 통과합니다.
  • ACTUAL은 파일경로 string이어야 합니다.

BeARegularFile

Expect(ACTUAL).To(BeARegularFile())
  • 파일이 ACTUAL위치에 있고 일반 파일이면 통과합니다.
  • ACTUAL은 파일경로 string이어야 합니다.

BeADirectory

Expect(ACTUAL).To(BeARegularFile())
  • 파일이 ACTUAL위치에 존재하고 디렉토리면 통과합니다.
  • ACTUAL은 파일경로 string이어야 합니다.

Working with Strings, JSON and YAML

ContainSubstring(substr string, args …interface{})

Expect(ACTUAL).To(ContainSubstring(STRING, ARGS...))
  • ACTUALfmt.Sprintf(STRING, ARGS...)을 포함하고 있으면 통과합니다.
  • ACTUALstring, []byte, Stringer(String()을 구현하고 있는)중 하나여야 합니다. 그렇지 않으면 에러가 발생합니다.

HavePrefix(prefix string, args …interface{})

Expect(ACTUAL).To(HaveSuffix(STRING, ARGS...))
  • ACTUALfmt.Sprintf(STRING, ARGS...)접미사를 가지고 있으면 통과합니다.
  • ACTUALstring, []byte, Stringer(String()을 구현하고 있는)중 하나여야 합니다. 그렇지 않으면 에러가 발생합니다.

MatchJSON(json interface{})

Expect(ACTUAL).To(MatchJSON(EXPECTED))
  • ACTUALEXPECTED가 같은 Object의 JSON표현이면 통과합니다.
  • ACTUALEXPECTED둘 다 string, []byte, Stringer(String()을 구현하고 있는)중 하나여야 합니다. 그렇지 않으면 에러가 발생합니다.
  • ACTUALEXPECTED를 파싱하여 결과를 reflect.DeppEqual로 비교합니다.
  • 그래서 빈문자열, 키 순서에 대해 문제가 발생하지 않습니다.
  • ACTUALEXPECTED둘다 올바른 JSON이 아니라면 에러가 발생합니다.

MatchXML(xml interface{})

Expect(ACTUAL).To(MatchXML(EXPECTED))
  • ACTUALEXPECTED가 같은 Object의 XML표현이면 통과합니다.
  • ACTUALEXPECTED둘 다 string, []byte, Stringer(String()을 구현하고 있는)중 하나여야 합니다. 그렇지 않으면 에러가 발생합니다.
  • ACTUALEXPECTED를 파싱하여 결과를 reflect.DeppEqual로 비교합니다.
  • 그래서 빈문자열, 키 순서에 대해 문제가 발생하지 않습니다.
  • ACTUALEXPECTED둘다 올바른 XML이 아니라면 에러가 발생합니다.

MatchYAML(yaml interface{})

Expect(ACTUAL).To(MatchYAML(EXPECTED))
  • ACTUALEXPECTED가 같은 Object의 YAML표현이면 통과합니다.
  • ACTUALEXPECTED둘 다 string, []byte, Stringer(String()을 구현하고 있는)중 하나여야 합니다. 그렇지 않으면 에러가 발생합니다.
  • ACTUALEXPECTED를 파싱하여 결과를 reflect.DeppEqual로 비교합니다.
  • 그래서 빈문자열, 키 순서에 대해 문제가 발생하지 않습니다.
  • ACTUALEXPECTED둘다 올바른 YAML이 아니라면 에러가 발생합니다.

Working with Collections

BeEmpty()

Expect(ACTUAL).To(BeEmpty())
  • ACTUAL이 empty면 통과합니다.
  • string, array, map, chan, slice타입만 가능하고 다른 타입은 에러가 발생합니다.

HaveLen(count int)

Expect(ACTUAL).To(HaveLen(INT))
  • ACTUAL의 길이가 INT와 같으면 통과합니다.
  • string, array, map, chan, slice타입만 가능하고 다른 타입은 에러가 발생합니다.

HaveCap(count int)

Expect(ACTUAL).To(HaveCap(INT))
  • ACTUAL의 capacity가 INT와 같으면 통과합니다.
  • array, chan, slice타입만 가능하고 다른 타입은 에러가 발생합니다.

ContainElement(element interface{})

Expect(ACTUAL).To(ContainElement(ELEMENT))
  • ACTUALELEMENT를 포함하고 있으면 통과합니다.
  • string, array, map, slice타입만 가능하고 다른 타입은 에러가 발생합니다.
  • map타입의 경우는 map의 키가아닌 값을 찾습니다.
  • 기본적으로 ContainElement()Equal()을 사용합니다. 하지만 인자로 GomegaMatcher를 사용할수도 있습니다.
Expect([]string{"Foo", "FooBar"}).To(ContainElement(ContainSubstring("Bar")))

ConsistOf(element …interface{})

Expect(ACTUAL).To(ConsistOf(ELEMENT1, ELEMENT2, ELEMENT3, ...))

or

Expect(ACTUAL).To(ConsistOf([]SOME_TYPE{ELEMENT1, ELEMENT2, ELEMENT3, ...}))
  • ACTUAL이 정확하게 요소들을 가지고 있으면 통과합니다.
  • 순서는 중요하지 않습니다.
  • 기본적으로 ConsistOf()Equal()을 사용합니다. 하지만 인자로 GomegaMatcher를 사용할수도 있습니다.
Expect([]string{"Foo", "FooBar"}).To(ConsistOf("FooBar", "Foo"))
Expect([]string{"Foo", "FooBar"}).To(ConsistOf(ContainSubstring("Bar"), "Foo"))
Expect([]string{"Foo", "FooBar"}).To(ConsistOf(ContainSubstring("Foo"), ContainSubstring("Foo")))
  • array, map, slice타입만 가능하고 다른 타입은 에러가
  • map타입의 경우는 map의 키가아닌 값을 찾습니다.
  • 다음과 같이 인자로 slice를 입력할 수도 있습니다.
Expect([]string{"Foo", "FooBar"}).To(ConsistOf([]string{"FooBar", "Foo"}))

HaveKey(key interface{})

Expect(ACTUAL).To(HaveKey(KEY))
  • ACTUALKEY키를 가지고 있으면 통과합니다.
  • ACTUAL은 반드시 map타입이어야 합니다.
  • 기본적으로 HaveKey()Equal()을 사용합니다. 하지만 인자로 GomegaMatcher를 사용할수도 있습니다.
Expect(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).To(HaveKey(MatchRegexp(`.+Foo$`)))

HaveKeyWithValue(key interface{}, value interface{})

Expect(ACTUAL).To(HaveKeyWithValue(KEY, VALUE))
  • ACTUAL이 키와 값이 같으면 통과합니다.
  • ACTUAL은 반드시 map타입이어야 합니다.
  • 기본적으로 HaveKeyWithValue()Equal()을 사용합니다. 하지만 인자로 GomegaMatcher를 사용할수도 있습니다.

Working with Numbers and Times

BeNumerically(comparator string, compareTo …interface{})

Expect(ACTUAL).To(BeNumerically(COMPARATOR_STRING, EXPECTED, <THRESHOLD>))
  • ACTUALEXPECTED는 숫자 타입이어야 합니다.
  • ACTUALEXPECTED가 숫자가 아니면 에러가 발생합니다.
  • Expect(ACTUAL).To(BeNumerically(“==”, EXPECTED)): 두 숫자가 수치적으로 같아야 합니다.
  • Expect(ACTUAL).To(BeNumerically(“~”, EXPECTED, )): asserts that ACTUAL and EXPECTED are within of one another. By default is 1e-8 but you can specify a custom value.
  • Expect(ACTUAL).To(BeNumerically(“>”, EXPECTED)): ACTUALEXPECTED보다 크면 통과합니다.
  • Expect(ACTUAL).To(BeNumerically(“>=”, EXPECTED)): ACTUAL가 EXPECTED보다 크거나 같으면 통과합니다.
  • Expect(ACTUAL).To(BeNumerically(“<”, EXPECTED)): ACTUALEXPECTED보다 작으면 통과합니다.
  • Expect(ACTUAL).To(BeNumerically(“<=”, EXPECTED)): ACTUALEXPECTED보다 작거나 같으면 통과합니다.

BeTemporally(comparator string, compareTo time.Time, threshold …time.Duration)

Expect(ACTUAL).To(BeTemporally(COMPARATOR_STRING, EXPECTED_TIME, <THRESHOLD_DURATION>))
  • 시간과 관련된 단정문을 작성할 때 사용됩니다.
  • ACTUAL은 반드시 time.Time타입이어야 합니다.

  • Expect(ACTUAL).To(BeTemporally(“==”, EXPECTED_TIME)): ACTUALEXPECTED_TIME과 같은 time.Time이면 통과합니다.
  • Expect(ACTUAL).To(BeTemporally(“~”, EXPECTED_TIME, )): asserts that ACTUAL and EXPECTED_TIME are within of one another. By default is time.Millisecond but you can specify a custom value.
  • Expect(ACTUAL).To(BeTemporally(“>”, EXPECTED_TIME)): asserts that ACTUAL is after EXPECTED_TIME.
  • Expect(ACTUAL).To(BeTemporally(“>=”, EXPECTED_TIME)): asserts that ACTUAL is after or at EXPECTED_TIME.
  • Expect(ACTUAL).To(BeTemporally(“<”, EXPECTED_TIME)): asserts that ACTUAL is before EXPECTED_TIME.
  • Expect(ACTUAL).To(BeTemporally(“<=”, EXPECTED_TIME)): asserts that ACTUAL is before or at EXPECTED_TIME.

Asserting on Panics

Panic()

Expect(ACTUAL).To(Panic())
  • ACTUAL이 함수이고 panic을 발생하면 통과합니다.
  • ACTUAL이 함수이고 아무런 argument가 없어야하고 결과도 아무런 결과를 리턴하지 않아야 합니다. 다른 타입들은 에러가 발생합니다.

Composing Matchers

Expect(number).To(SatisfyAll(
            BeNumerically(">", 0),
            BeNumerically("<", 10)))

Expect(msg).To(SatisfyAny(
            Equal("Success"),
            MatchRegexp(`^Error .+$`)))
  • 또는 다음과 같이 만들어 사용할 수 있습니다.
func BeBetween(min, max int) GomegaMatcher {
    return SatisfyAll(
            BeNumerically(">", min),
            BeNumerically("<", max))
}

Expect(number).To(BeBetween(0, 10))

And(matchers …GomegaMatcher) SatisfyAll(matchers …GomegaMatcher)

Expect(ACTUAL).To(And(MATCHER1, MATCHER2, ...))
Expect(ACTUAL).To(SatisfyAll(MATCHER1, MATCHER2, ...))
  • ACTUAL이 모든 MATCHER들을 만족하면 통과합니다.
  • 순서대로 matcher들을 테스트 하고 도중에 실패하면 즉시 실패합니다.

Or(matchers …GomegaMatcher) SatisfyAny(matchers …GomegaMatcher)

Expect(ACTUAL).To(Or(MATCHER1, MATCHER2, ...))
Expect(ACTUAL).To(SatisfyAny(MATCHER1, MATCHER2, ...))
  • ACTUAL이 MATCHER들중 하나라도 만족하면 통과합니다.
  • 순서대로 matcher들을 테스트 하고 도중에 하나라도 통과하면 즉시 통과하고 남은 것들은 테스트하지 않습니다.

Not(matcher GomegaMatcher)

Expect(ACTUAL).To(Not(MATCHER))
  • ACTUAL이 Matcher를 통과하지 않다면 통과합니다.

WithTransform(transform interface{}, matcher GomegaMatcher)

Expect(ACTUAL).To(WithTransform(TRANSFORM, MATCHER))
  • ACTUALTRANSFORM함수를 이용하여 변형하여 Matcher를 통과하면 통과합니다.
GetColor := func(e Element) Color { return e.Color }

Expect(element).To(WithTransform(GetColor, Equal(BLUE)))
  • 혹은 다음과 같이 만들어서 사용할 수 있습니다.
// HaveColor returns a matcher that expects the element to have the given color.
func HaveColor(c Color) GomegaMatcher {
    return WithTransform(func(e Element) Color {
        return e.Color
    }, Equal(c))
}

Expect(element).To(HaveColor(BLUE)))