jarcoal/httpmock

Mock not working

Vindusha opened this issue · 5 comments

I have my http client using transport : [ client := &http.Client{Transport: tr} ]. When I do a mock on this, it fails. Whereas if I remove the transport [ client := &http.Client{} ], it works. Could you please explain a solution to this issue ?

Hi, could you provide a simple test file so we can reproduce your problem?

import (
	"crypto/tls"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"testing"

	"github.com/jarcoal/httpmock"
	"github.com/pkg/errors"
)

var trs = &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

func RequestDetails() (request string, err error) {
	client := &http.Client{Transport: trs}

	req, err := http.NewRequest("http://localhost:8080/request", "GET", nil)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	req.Header.Add("Content-Type", "application/json")

	res, err := client.Do(req)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	err = json.Unmarshal([]byte(body), &request)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	return request, nil
}

func TestRequestDetails(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	httpmock.RegisterResponder("GET", "/request",
		httpmock.NewStringResponder(200, `{"key1":"value1"}`))

	res, _ := RequestDetails()

	if res != "" {
		t.Logf("Success")
	} else {
		t.Errorf("Failure")
	}
}

This is my test file. And the test always fails.

As explained in httpmock.Activate doc:

Under the hood this replaces the Transport on the http.DefaultClient with httpmock.DefaultTransport.

In your test, you don't use http.DefaultClient neither httpmock.DefaultTransport, so the mock is not effective.

changing your trs definition to:

var trs http.RoundTripper = &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

then doing in TestRequestDetails(), before calling RequestDetails():

trs = httpmock.DefaultTransport

should do the work.

var trs http.RoundTripper = &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

func RequestDetails() (request string, err error) {
	client := &http.Client{Transport: trs}

	req, err := http.NewRequest("http://localhost:8080/request", "GET", nil)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	req.Header.Add("Content-Type", "application/json")

	res, err := client.Do(req)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	err = json.Unmarshal([]byte(body), &request)
	if err != nil {
		return request, errors.Wrap(err, "Request Not Found")
	}

	return request, nil
}

func TestRequestDetails(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	trs = httpmock.DefaultTransport
	
	httpmock.RegisterResponder("GET", "/request",
		httpmock.NewStringResponder(200, `{"key1":"value1"}`))

	res, _ := RequestDetails()

	if res != "" {
		t.Logf("Success")
	} else {
		t.Errorf("Failure")
	}
}

I made the following changes. But still it fails.

Your code is full of bugs not related to httpmock:

  • bad use of http.NewRequest
  • you can't json.Unmarshal a JSON map in a string

read the error your function RequestDetails() returns, otherwise no need to return an error.