将函数拆分为两个函数以进行测试覆盖。

huangapple go评论82阅读模式
英文:

Split function into 2 function for test coverage

问题

我应该如何测试ioutil.ReadAll(rep.Body)的错误?我需要将我的函数分成两部分吗?一部分用于发起请求,另一部分用于读取响应体并返回字节和错误。

func fetchUrl(URL string) ([]byte, error) {
  resp, err := http.Get(URL)
  if err != nil {
    return nil, err
  }
  body, err := ioutil.ReadAll(resp.Body)
  resp.Body.Close()
  if err != nil {
    return nil, err
  }
  return body, nil
}
英文:

How can I test the error for ioutil.ReadAll(rep.Body)? Do I need to split my function in two, one which will make the request, and another one which will read the body and return the bytes and error?

func fetchUrl(URL string) ([]bytes, error) {
  resp, err := http.Get(URL)
  if err != nil {
    return nil, err
  }
  body, err := ioutil.ReadAll(resp.Body)
  resp.Body.Close()
  if err != nil {
    return nil, err
  }
  return body, nil
}

答案1

得分: 2

基本上是的,除非你在测试时使用net/http/httptest或类似的方式来模拟你的HTTP服务器。

但问题是:你真正要测试什么?是ioutil.ReadAll()是否能检测到错误?但我确信这已经在Go标准库的测试套件中得到了覆盖。

因此,在这种特殊情况下,我认为你只是为了测试而测试。在我看来,对于这种琐碎的情况,更好的做法是集中精力处理获取到的结果。

英文:

Basically yes, unless you're using net/http/httptest or a similar way to mock your HTTP server when testing.

But the question is: what would you really be testing? That ioutil.ReadAll() detects errors? But I'm sure this was already covered by the test suite of the Go's stdlib.

Hence I'd say that in this particular case you're about to test for the testing's sake. IMO for such trivial cases it's better to concentrate on how the fetched result is further processed.

答案2

得分: 2

我需要将我的函数分成两部分吗?一个用于发送请求,另一个用于读取响应体并返回字节和错误信息?

第一个函数是http.Get,第二个函数是ioutil.ReadAll,所以我认为没有必要进行分割。你只是创建了一个使用两个其他函数的函数,假设这两个函数都能正常工作。你甚至可以简化你的函数,使其更加明显:

func fetchURL(URL string) ([]byte, error) {
    resp, err := http.Get(URL)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    return ioutil.ReadAll(resp.Body)
}

如果你想测试fetchURL函数是否使用了http.Getioutil.ReadAll,我个人不会费心直接测试它,但如果你坚持要测试,你可以为单个测试覆盖http.DefaultTransport,并提供自己的RoundTripper,它返回具有某些错误场景的http.Response(例如,在读取响应体时出现错误)。

以下是一个简要的示例:

type BrokenTransport struct {
}

func (*BrokenTransport) RoundTrip(*http.Request) (*http.Response, error) {
    // 返回具有特定错误行为的 Response
}

http.DefaultTransport = &BrokenTransport{}

// 现在,http.Get将使用你的 RoundTripper。
// 在测试结束后,你应该恢复 http.DefaultTransport。

希望对你有帮助!

英文:

> Do I need to split my function in two, one which will make the request, and another one which will read the body and return the bytes and error?

The first one is called http.Get and the other one ioutil.ReadAll, so I don't think there's anything to split. You just created a function that uses two other functions together which you should assume are working correctly. You could even simplify your function to make it more obvious:

func fetchURL(URL string) ([]byte, error) {
	resp, err := http.Get(URL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

If you want to test anything is your fetchURL function using http.Get and ioutil.ReadAll together. I wouldn't personally bother to test it directly, but if you insist on it, you can overwrite http.DefaultTransport for a single test and provide your own, which returns http.Response with body implementing some error scenarios (e.g. and error during body read).

Here is the sketch idea:

type BrokenTransport struct {
}

func (*BrokenTransport) RoundTrip(*http.Request) (*http.Response, error) {
	// Return Response with Body implementing specific error behaviour
}

http.DefaultTransport = &BrokenTransport{}

// http.Get will now use your RoundTripper.
// You should probably restore http.DefaultTransport after the test.

huangapple
  • 本文由 发表于 2015年12月29日 19:28:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/34510055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定