h2non / gock

HTTP traffic mocking and testing made easy in Go ༼ʘ̚ل͜ʘ̚༽

Home Page:https://pkg.go.dev/github.com/h2non/gock

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

When in networking mode and mock matches still NativeTransport.RoundTrip response used if error occurs

dnldaniel opened this issue · comments

Hi,

I test my application A using it's HTTP API. During the test my application calls application B using HTTP API. I would like to mock application B response using gock. I've learned that I have to use networking mode, otherwise my calls to A would fail.

However, even though I created a mock that matches the request issued by application A towards application B, it is not used because of code lines below with my comments added (link to the code in github):

if networking { // true
	res, err = m.Transport.RoundTrip(req) // res == nil, err != nil
	// In no mock matched, continue with the response
	if err != nil || mock == nil { // as err from native transport is not nil, because app B host cannot be reached, native transport res is returned
		return res, err // line reached and nil res returned with non-nil err
	}
}

return Responder(req, mock.Response(), res)

From the gock's readme I understood that mock takes precedence over NativeTransport in networking mode. The comment from this line additionally enforces me in such understanding. What's your view?

Daniel

commented

I agree this behaviour is not as versatile as it should be. I see multiple acceptable scenarios here that would depend on the developer's expectations.

The underlying idea of having networking mode is in order to have real requests and merge the response with the defined mock, if it was matched. However, there are legit situations where this is now desired.

These are the scenarios I see we can cover when networking mode is enabled:

  1. [covered] mock matched, real HTTP return a response = responses are merged and the result is returned.
  2. [covered] mock is not matched, real HTTP return a response = real response is returned.
  3. [covered] mock is not matched, real HTTP fails = error is returned
  4. [missing] mock is matched, real HTTP fails = error is returned (current behavior) but we may want to use the mock here instead.

Note: this scenarios do not consider HTTP protocol level errors, only network errors.

For the 4) scenario I see use cases where we want to fail and others where not.
In most cases, you would simply prefer to do not enable networking mode, but in the very few where you want to do it, I think an additional behaviour configuration should be added to make this explicit.
E.g: gock.SetNetworkingConfig(gock.NetworkingConfig{ReturnErrors: false})

Opinions?

For the 4) scenario I see use cases where we want to fail and others where not.

If real HTTP fails (no response, just error when establishing connection) but mock is matched, what would be the use case that would make mock returned undesirable?

Well, obviously from my point of view the best solution would be to change behavior such that when mock is matched and error from real HTTP is returned then Responder(req, mock.Response(), res) is returned. But configuration setting seems to be a good option too. Regarding the following proposal:
gock.SetNetworkingConfig(gock.NetworkingConfig{ReturnErrors: false})
It assumes that developer using gock knows implementation details thus concludes that when ReturnErrors: false then matched mock is used over erroneous http response. Well, its ok with me as it's going to still fulfill my need, but if I can put my two cents, I would change the configuration setting to use case oriented one, like:
gock.SetNetworkingConfig(gock.NetworkingConfig{MockOverHttp: true}) with default value false.
In such case, even when networking mode is enabled, if mock is matched it is always returned without even trying to do NativeTransport roundtrip. Of course that goes in conflict with 1st scenario you mentioned (merging real http and mock).