Go-github: Mock Create repo/issue calls

Created on 31 May 2019  路  6Comments  路  Source: google/go-github

Hi Folks -

Is there a go-github proto file available anywhere? The benefit of it would be to generate github client files which would be immensely helpful for mocking out requests and running tests locally.

Many thanks

Most helpful comment

Yes, Go makes it relatively straightforward to mock functions using interfaces.

Here is a super-simplified example that will hopefully get you started... please let me know if you have any questions.

First, the main.go program under test which, by itself, will call the actual GitHub API:

package main

import (
    "context"

    "github.com/davecgh/go-spew/spew"
    "github.com/google/go-github/github"
)

type issueCreator interface {
    Create(ctx context.Context, owner string, repo string, issue *github.IssueRequest) (*github.Issue, *github.Response, error)
}

type issuesClient struct {
    ctx          context.Context
    issuesClient issueCreator
}

func main() {
    ctx := context.Background()
    client := github.NewClient(nil)

    ic := &issuesClient{ctx: ctx, issuesClient: client.Issues}
    ic.UnderTest()
}

func (ic *issuesClient) UnderTest() error {
    labels := []string{"label1"}
    req := &github.IssueRequest{
        Title:    github.String("title"),
        Body:     github.String("body"),
        Assignee: github.String("assignee"),
        Labels:   &labels,
    }
    issue, _, err := ic.issuesClient.Create(ic.ctx, "owner", "repository", req)
    if err != nil {
        return err
    }
    spew.Dump(issue)
    return nil
}

Next, here is the main_test.go program that mocks the one GitHub API endpoint that you asked for above and go test will not actually call the GitHub API, which is what I believe you mean by "mocking":

package main

import (
    "context"
    "testing"

    "github.com/google/go-github/github"
)

type mockClient struct {
    resp *github.Issue
}

func (m *mockClient) Create(ctx context.Context, owner, repo string, issue *github.IssueRequest) (*github.Issue, *github.Response, error) {
    return m.resp, nil, nil
}

func TestUnderTest(t *testing.T) {
    ctx := context.Background()
    mc := &mockClient{
        resp: &github.Issue{
            ID: github.Int64(1),
        },
    }
    ic := &issuesClient{ctx: ctx, issuesClient: mc}
    if err := ic.UnderTest(); err != nil {
        t.Fatalf("UnderTest: %v", err)
    }
}

I hope that helps.

All 6 comments

"Proto" as in gRPC "protobuf"?
Can you please point us to an example of what you are talking about?

hey again, ah you're right proto files are for gRPC only. Never mind.. I'll close this issue.
I'm just trying to mock create repo/issue related calls, but haven't been successful.
On second though, I'll just update the title of the issue...

Glen, perhaps you'd be able to help.

x := &github.IssueRequest{Title: title, Body: body, Assignee: assignee, Labels: labels}
    _, issue, err := client.Issues.Create(ctx, owner, repository, x)

which works as it is supposed to, and creates an issue in the defined repo, however what I'm trying to accomplish is to mock out client.Issues.Create().
Is there a way to accomplish this?

Yes, Go makes it relatively straightforward to mock functions using interfaces.

Here is a super-simplified example that will hopefully get you started... please let me know if you have any questions.

First, the main.go program under test which, by itself, will call the actual GitHub API:

package main

import (
    "context"

    "github.com/davecgh/go-spew/spew"
    "github.com/google/go-github/github"
)

type issueCreator interface {
    Create(ctx context.Context, owner string, repo string, issue *github.IssueRequest) (*github.Issue, *github.Response, error)
}

type issuesClient struct {
    ctx          context.Context
    issuesClient issueCreator
}

func main() {
    ctx := context.Background()
    client := github.NewClient(nil)

    ic := &issuesClient{ctx: ctx, issuesClient: client.Issues}
    ic.UnderTest()
}

func (ic *issuesClient) UnderTest() error {
    labels := []string{"label1"}
    req := &github.IssueRequest{
        Title:    github.String("title"),
        Body:     github.String("body"),
        Assignee: github.String("assignee"),
        Labels:   &labels,
    }
    issue, _, err := ic.issuesClient.Create(ic.ctx, "owner", "repository", req)
    if err != nil {
        return err
    }
    spew.Dump(issue)
    return nil
}

Next, here is the main_test.go program that mocks the one GitHub API endpoint that you asked for above and go test will not actually call the GitHub API, which is what I believe you mean by "mocking":

package main

import (
    "context"
    "testing"

    "github.com/google/go-github/github"
)

type mockClient struct {
    resp *github.Issue
}

func (m *mockClient) Create(ctx context.Context, owner, repo string, issue *github.IssueRequest) (*github.Issue, *github.Response, error) {
    return m.resp, nil, nil
}

func TestUnderTest(t *testing.T) {
    ctx := context.Background()
    mc := &mockClient{
        resp: &github.Issue{
            ID: github.Int64(1),
        },
    }
    ic := &issuesClient{ctx: ctx, issuesClient: mc}
    if err := ic.UnderTest(); err != nil {
        t.Fatalf("UnderTest: %v", err)
    }
}

I hope that helps.

@gmlewis you are the man. A million thanks for your thorough and phenomenal response.

Thank you, @jkalandaibm!
Closing issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

you06 picture you06  路  3Comments

zulhfreelancer picture zulhfreelancer  路  3Comments

scriptonist picture scriptonist  路  3Comments

smola picture smola  路  3Comments

gmlewis picture gmlewis  路  3Comments