Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fake Client (feature request) #2024

Closed
RafaeLeal opened this issue Jul 27, 2021 · 4 comments
Closed

Fake Client (feature request) #2024

RafaeLeal opened this issue Jul 27, 2021 · 4 comments

Comments

@RafaeLeal
Copy link

Hi!
My team has been using this client a lot to integrate our new CICD tool (Tekton) with Github. Thanks, btw! It mostly "just works" :)
To test these integrations, we implemented a simple fake client. I'd like to ask if a PR adding a fake client would be welcome.
This would require us to add interfaces for the client and its services..

Just a quick view of how that would look like:

package github

import (
	"context"
	"net/http"
)

type ChecksServiceInterface interface {
	//TODO finish me
	GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error)
	CreateCheckRun(ctx context.Context, owner, repo string, opts CreateCheckRunOptions) (*CheckRun, *Response, error)
	UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opts UpdateCheckRunOptions) (*CheckRun, *Response, error)
	ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opts *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error)
}

type RepositoriesServiceInterface interface {
	//TODO finish me
	ListHooks(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Hook, *Response, error)
}

type IssuesServiceInterface interface {
	//TODO finish me
	CreateComment(ctx context.Context, owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error)
}

type Interface interface {
	//TODO finish me
	ChecksService() ChecksServiceInterface
	RepositoriesService() RepositoriesServiceInterface
	IssuesService() IssuesServiceInterface
	RateLimits(ctx context.Context) (*RateLimits, *Response, error)
}

func NewClientInterface(httpClient *http.Client) Interface {
	return NewClient(httpClient)
}

func (g *Client) ChecksService() ChecksServiceInterface {
	return g.Checks
}

func (g *Client) RepositoriesService() RepositoriesServiceInterface {
	return g.Repositories
}

func (g *Client) IssuesService() IssuesServiceInterface {
	return g.Issues
}

Then you could use the client though the interfaces:

githubClient := github.NewClientInterface(nil) // type github.Interface
_, _, err := githubClient.ChecksService().CreateCheckRun(...)
...

And it would be the same for fake client

githubClient := fakegithub.NewFakeClient(nil) // type github.Interface
_, _, err := githubClient.ChecksService().CreateCheckRun(...)
...
@gmlewis
Copy link
Collaborator

gmlewis commented Jul 27, 2021

Thank you, @RafaeLeal - this sounds cool! Before we proceed any further, could you please take a moment and read through #1800 since I think that is relevant.

We might recommend creating your fakegithub client in a separate repo (under your own corporate or personal GitHub username). Please let us know what you think after reading that discussion. (Sorry, but the discussion itself got branched out all over the place.)

@RafaeLeal
Copy link
Author

RafaeLeal commented Jul 27, 2021

Thanks for the link, I read some of the discussion..

In my case, I don't need to embed interfaces into the struct, but I'd benefit from having interfaces for the client.
Although I could (and we already did actually) add interfaces on our side, I can not implement methods for the GitHub client.
So if we want to have a GitHub client interface as I showed I need to write a wrapper for the GitHub client.

type githubClient struct {
	client *github.Client
}

func New() (Interface, error) {
	gh, err := client.NewGithubClient()
	if err != nil {
		return nil, err
	}
	return &githubClient{client: gh}, nil
}

func (g *githubClient) ChecksService() ChecksServiceInterface {
	return g.client.Checks
}

func (g *githubClient) RepositoriesService() RepositoriesServiceInterface {
	return g.client.Repositories
}

func (g *githubClient) IssuesService() IssuesServiceInterface {
	return g.client.Issues
}

and this type of code seems a bad smell since it's going to require us to keep with the changes inside this repo.

I can't simply use

githubClient := github.NewClient(nil) // returns *github.Client
githubClient.Checks.CreateCheckRun(...)

because we need the interfaces to fake them

@migueleliasweb
Copy link
Contributor

migueleliasweb commented Aug 2, 2021

Hi @RafaeLeal , after lots of conversations and feedback about this topic from the folks from go-github, I've help create a separate repo to address this functionality. I had a similar issue as I needed to unittest my code that uses the go-github SDK. Cheers!

Have a look: https://github.com/google/go-github#testing-code-that-uses-go-github

@gmlewis
Copy link
Collaborator

gmlewis commented Aug 6, 2021

Closing feature request. Please let us know (or submit a PR that updates README.md) if you decide to create another external helper repo that we can point to, @RafaeLeal .

@gmlewis gmlewis closed this as completed Aug 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants