douyong1885 2018-12-20 17:04
浏览 13
已采纳

具有依赖项注入的测试包装功能

I have this function which I need to mock in test, I was able to mock it as expected with http mock package , but now I’ve function that are calling To the HttpReq method and here I cannot use http mock package I read about dependency injection and tried something but I wasn’t able to fully do it,

This is the function

type params struct {
    cs     string
    ci     string
    method string
    url    string
}

// I added this struct but not sure if it's needed ... probably for test purpose but not sure how to use it.

type Impl struct {
 client *http.Client
}

func (i *Impl) HttpReq(p *params) ([]byte, error) {
    httpClient := i.client
    req, err := http.NewRequest(p.method, p.url, nil)
    if err != nil {
        fmt.Sprintf(err)
    }
    req.SetBasicAuth(p.cs, p.ci)
    res, err := httpClient.Do(req)
    if err != nil {
        fmt.Sprintf(err)
    }
    t, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Sprintf(err)
    }
    defer res.Body.Close()
    return t, nil
}

This is what I tried

I’ve created interface

type Req interface {
    HttpReq(params) ([]byte, error)
}

Now I’ve created a struct which contain the interface

type Service struct {
    req Req
}

This is the function which I need to tests

func (c *Service) execute(cli Connection , args []string) (error, []byte) {
    sk, err := c.doSomthing(cli, args)

    sc, err := c.doSometing2(serviceK, []string{"url", "cl", "ct"})

    cc := strings.Fields(serviceCredentials)

    // ----------Here is what I need to mock ----------
    t, err := c.req.HttpReq(params{cs: cc[1],
        ci:     cc[2],
        method: http.MethodPost,
        url:    cc[0],})
    return err, t
}

Any idea how I can run test for this function ??? Im struggling with it a lot.

  • 写回答

2条回答 默认 最新

  • douwu7168 2018-12-20 17:40
    关注

    Independent of the original question, you should not create new HTTP clients for each request. Client's maintain a connection pool and should be reused as much as possible.

    You can fix that, and continue using your existing mock server by injecting the HTTP client.

    Note also that the interface definition in the question doesn't match the implementation. These two method signatures are not the same:

    HttpReq(params) ([]byte, error)  // Req
    HttpReq(*params) ([]byte, error) // Impl
    

    Pick one. I would probably go with the non-pointer type here. And upper case initials are idiomatic in Go (HTTPReq, not HttpReq).

    Add the client to the Impl type and use it in HTTPReq:

    type Impl struct {
        client *http.Client
    }
    
    func (i *Impl) HTTPReq(p params) ([]byte, error) {
        req, err := http.NewRequest(p.method, p.url, nil)
        if err != nil {
            return nil, err
        }
        req.SetBasicAuth(p.cs, p.ci)
    
        res, err := i.client.Do(req)
        if err != nil {
            return nil, err
        }
        defer res.Body.Close()
    
        return ioutil.ReadAll(res.Body)
    }
    

    The Service type doesn't have to change.

    In the tests, simply inject a test client into the Impl value:

    import (
        "context"
        "net"
        "net/http"
        "net/http/httptest"
        "testing"
    )
    
    func TestService_execute(t *testing.T) {
        var testHandler http.Handler // TODO
    
        srv := httptest.NewServer(testHandler)
        defer srv.Close()
    
        client := srv.Client()
        tp := client.Transport.(*http.Transport)
    
        // Direct all requests to the test server, no matter what the request URL is.
        tp.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
            // Note that we ignore the network and addr parameters, since these are 
            // derived from the request URL and are unrelated to the test server.
    
            srvAddr := srv.Listener.Addr()
            return (&net.Dialer{}).DialContext(ctx, srvAddr.Network(), srvAddr.String())
        }
    
        svc := &Service{
            req: &Impl{
                client: client,
            },
        }
    
        svc.execute(/* ... */)
    
        // assert request, response, etc.
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥15 统计大规模图中的完全子图问题
  • ¥15 使用LM2596制作降压电路,一个能运行,一个不能
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路
  • ¥15 phython读取excel表格报错 ^7个 SyntaxError: invalid syntax 语句报错
  • ¥20 @microsoft/fetch-event-source 流式响应问题
  • ¥15 ogg dd trandata 报错
  • ¥15 高缺失率数据如何选择填充方式