Go: mock-объект для API

Внутри наших сервисов рано или поздно появятся использование внешнего API, которое может вести себя как угодно. В то время когда для тестирование приложения нам бы хотелось иметь что-то более предсказуемое. И здесь нам на помощь приходит пакет net/http/httptest. Рассмотрим как он нам может помочь. Пусть у нас есть объект пользователя

type User struct {
  Id      int
  Rating  int
  Counter int
}

Пользователя мы получаем путем вызова API-метода

func ApiCaller(user *User, url string) error {
  resp, err := http.Get(url)
  if err != nil {
    return err
  }
  defer resp.Body.Close()
  return updateUser(user, resp.Body)
}

Результатом, которого является json представление объекта

type JsonResponse struct {
  Result string `json:"result"`
  Data struct {
    UserId int `json:"user_id"`
    Rating int `json:"rating"`
  } `json:"data"`
}

а после updateUser заполняет поля User из полей объекта JsonResponse.

func updateUser(user *User, closer io.ReadCloser) error {
	body, err := ioutil.ReadAll(closer)
	if err != nil {
		return err
	}
	result := JsonResponse{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}
	if result.Result == success {
		user.Id = result.Data.UserId
		user.Counter ++
		user.Rating = result.Data.Rating
	}
	return nil
}

Для использование httptest в качестве mock-объекта нужно создать новый сервер при его помощи, после чего передать его адрес в метод ApiCaller

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      w.Header().Set("Content-Type", "application/json; charset=utf-8")
      fmt.Fprintln(w, `{
  "result": "ok",
  "data": {
    "user_id": 1,
    "rating": 42
  }
}`)
   }))
   defer ts.Close()

   user := User{id: 1}
   err := ApiCaller(&user, ts.URL)

здесь ts.URL будет содержать строку вида http://127.0.0.1:49799, которая и будет моком.

 

07.10.2018









 
архив

подписка