Project: Gloo (Orchestration & Management / API Gateway)
File: writing-tests.md

- - - - All new packages and most new significant functionality must come with unit tests Table-driven tests are preferred for testing multiple scenarios/inputs Significant features should come with and/or Tests which are platform-dependent, should be marked as such using Gomega has a powerful set of built-in matchers. We recommend using these matchers whenever possible. You can find the full list of matchers . We have a number of custom matchers that we use in our tests. These are defined in a . If you find yourself writing a custom matcher, consider adding it to this package. It is possible to . Transforms are either: functions which accept one parameter that returns one value functions which accept one parameter that returns two values, where the second value must be of the error type Transforms allow us to re-use matchers, and convert the data that we want to compare into a format that the matcher can understand. Below are a couple examples that illustrate this concept. Let's say you want to compare that an integer value contains a specific substring: ```go Expect(12345).To(ContainSubstring("234")) ``` You can't use the `ContainSubstring` matcher, because it only works on strings. You can use a transform to convert the integer to a string: ```go WithTransform(strconv.Itoa, {MATCHER}) ``` Now we can rewrite our assertion as: ```go Expect(12345).To(WithTransform(strconv.Itoa, ContainSubstring("234"))) ``` Let's say we want to compare the data returned by an http.Response to a key/value pair: ```go Expect(response).To(HaveKeyWithValue("status", 200)) ``` This doesn't work, because the response (*http.Response) is not a map[string]interface{}, so we can't use the standard `HaveKeyWithValue` matcher. We can use a transform to convert the response into a map[string]interface{}: ```go WithTransform(transforms.WithJsonBody(), {MATCHER}) ``` Now we can rewrite our assertion as: ```go Expect(response).To(WithTransform(transforms.WithJsonBody(), HaveKeyWithValue("status", 200))) ``` We have a few custom matchers that we use in our tests. These are defined in a . If you find yourself writing a custom transform, consider adding it to this package. A common pattern to assert than an error occurred ```go Expect(err).To(HaveOccurred()) ``` A more explict way to perfrom this assertion is: ```go Expect(err).To(MatchError("expected error")) ``` or ```go Expect(err).To(MatchError(GlobalError)) ``` or ```go Expect(err).To(MatchError(ErrorFunc("expected error")) ``` or ```go Expect(err).To(MatchError(GlobalError)) ``` or ```go Expect(err).To(MatchError(ErrorFunc("expected error")) ``` Sometimes you will see: ```go // the list should be empty because it was initialized with no items Expect(list).To(BeEmpty()) ``` However, you can optionally supply a description to an assertion, which allows you to collapse the comment directly into the assertion ```go Expect(list).To(BeEmpty(), "list should be empty on initialization") ``` We support a custom Matcher, to validate a *http.Response. This matcher is useful when you want to validate the response body, headers, status code, etc. For example: ```go Expect(response).To(HaveHttpResponse(&HttpResponse{ StatusCode: http.StatusOK, Body: gomega.ContainSubstring("body substring"), Headers: map[string]interface{}{ "x-solo-resp-hdr1": Equal("test"), }, Custom: // your custom match logic, })) ```