Unit test with http as dependency for wrapper func

2020-03-31 05:52发布

I’ve the following function which after help of @poy I was able to create mock for it in order to unit test it.

The issue now that I’ve wrapper function which needs also to be tested

This is the original function which have working test

func httpReq(cc []string, method string, url string) ([]byte, error) {
    httpClient := http.Client{}
    req, err := http.NewRequest(method, url, nil)
    if err != nil {
        return nil, errors.Wrap(err, "failed to execute http request")
    }
    //Here we are passing user and password
    req.SetBasicAuth(cc[1], cc[2])
    res, err := httpClient.Do(req)
    if err != nil {
        fmt.error(err)
    }
    val, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.error(err)
    }
    defer res.Body.Close()
    return val, nil
}

This is the test which works as expected, this test use https://golang.org/pkg/net/http/httptest/ in order to mock http requests.

func Test_httpReq(t *testing.T){

  expectedValue = "some-value"
  server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){

    u,p,ok := r.BasicAuth()
    if !ok || u != "fakeuser" || p != "fakepassword" {
      t.Fatal("wrong auth")
    }
    w.Write([]byte(expectedValue))
  })

  val, err := httpReq(
   []string{"fakeuser", "fakepassword"}, 
   http.MethodPost, 
   server.URL,
  )

  if err != nil{
    t.Fatal(err)
  }

  if val != expectedValue {
    t.Fatalf("expected %q to equal %q", val, expectedValue)
  }

Now the issue is that I’ve another function which call to the above function which needs to be tested also.

This is the function which use httpReq and I need to create test also for it

func (c *Service) invoke(Connection Connection, args []string) {
    service, err := c.getService(Connection, args)

    serviceC, err := c.getServiceK(service, []string{"url", “user”, “id”})
    c := strings.Fields(serviceC)
        //—————Here we are using the http function again 
    val, err := httpReq(c[1], c[1],”post”, c[0])
    if err != nil {
        fmt.println(err)
    }
    fmt.Print(string(val))
}

Now when I use the test for it I got error inside the http request method since here I cannot mock the http.

Is there any technique In Golang Which can help which this kind of scenario? I've search about it, something like dependency injection and found that maybe interface could help, but since this is http I'm not sure how to do it.

Any example with this context will be very helpful to me.

1条回答
一夜七次
2楼-- · 2020-03-31 06:32

Service object can have an interface like this

type Service struct {
    serviceK typeK
    serviceHttp serviceHttp // of type interface hence can be mocked
}

Normal application code can init services with actual objects. Tests will have mocks objects

type Req struct {
}

type Resp struct {
}

type ServiceHttp interface{
    HttpReq(params Req)(Resp, error)
}

type Implementation struct {
}

func (i *Implementation)HttpReq(params Req)(Resp, error){
   // buid http request
}

func (c *Service) invoke(Connection Connection, args []string) {

    service, err := c.getService(Connection, args)

    serviceC, err := c.getServiceK(service, []string{"url", “user”, “id”})
    c := strings.Fields(serviceC)

    serviceImp := c.GetServiceImp()

    // init params with the required fields
    val, err := c.HttpReq(params)
    if err != nil {
      fmt.println(err)
    }
    fmt.Print(string(val))

}

when you are running tests, you can initialise the service object with mock Implementation that returns a dummy response.

type MockImplementation struct {
}

func (i *MockImplementation)HttpReq(Resp, error){
    // return mock response
}

func TestMain(){
  services := {
     serviceHttp:MockImplementation{},
     serviceK: typeK{}, // initialise this
  }
}

This is one of way testing it. Other way could be I guess where httpReq return http.ResponseWriter and you can use httptest.ResponseRecorder to test it.

查看更多
登录 后发表回答