Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/migueleliasweb/go-github-mock
A library to aid unittesting code that uses Golang's Github SDK
https://github.com/migueleliasweb/go-github-mock
github go go-github golang mock mocking sdk testing
Last synced: 3 months ago
JSON representation
A library to aid unittesting code that uses Golang's Github SDK
- Host: GitHub
- URL: https://github.com/migueleliasweb/go-github-mock
- Owner: migueleliasweb
- License: mit
- Created: 2021-07-21T05:45:43.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-05-26T11:49:44.000Z (6 months ago)
- Last Synced: 2024-06-18T14:14:50.051Z (5 months ago)
- Topics: github, go, go-github, golang, mock, mocking, sdk, testing
- Language: Go
- Homepage:
- Size: 123 KB
- Stars: 92
- Watchers: 2
- Forks: 22
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# go-github-mock
[![Go Reference](https://pkg.go.dev/badge/github.com/migueleliasweb/go-github-mock.svg)](https://pkg.go.dev/github.com/migueleliasweb/go-github-mock) [![Go Report Card](https://goreportcard.com/badge/github.com/migueleliasweb/go-github-mock)](https://goreportcard.com/report/github.com/migueleliasweb/go-github-mock)A library to aid unittesting code that uses Golang's Github SDK
## Installation
```bash
go get github.com/migueleliasweb/go-github-mock
```## Features
- Create mocks for successive calls for the same endpoint
- Pagination support (see `mock.WithRequestMatchPages`)
- Mock error returns
- High level abstraction helps writing readabe unittests (see `mock.WithRequestMatch`)
- Lower level abstraction for advanced uses (see `mock.WithRequestMatchHandler`)
- Mock rate limiting errors from the api (see `mock.WithRateLimit`)## Examples
```go
import "github.com/migueleliasweb/go-github-mock/src/mock"
```### Multiple requests
```golang
mockedHTTPClient := mock.NewMockedHTTPClient(
mock.WithRequestMatch(
mock.GetUsersByUsername,
github.User{
Name: github.String("foobar"),
},
),
mock.WithRequestMatch(
mock.GetUsersOrgsByUsername,
[]github.Organization{
{
Name: github.String("foobar123thisorgwasmocked"),
},
},
),
mock.WithRequestMatchHandler(
mock.GetOrgsProjectsByOrg,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Write(mock.MustMarshal([]github.Project{
{
Name: github.String("mocked-proj-1"),
},
{
Name: github.String("mocked-proj-2"),
},
}))
}),
),
)
c := github.NewClient(mockedHTTPClient)ctx := context.Background()
user, _, userErr := c.Users.Get(ctx, "myuser")
// user.Name == "foobar"
orgs, _, orgsErr := c.Organizations.List(
ctx,
*(user.Name),
nil,
)// orgs[0].Name == "foobar123thisorgwasmocked"
projs, _, projsErr := c.Organizations.ListProjects(
ctx,
*orgs[0].Name,
&github.ProjectListOptions{},
)// projs[0].Name == "mocked-proj-1"
// projs[1].Name == "mocked-proj-2"```
### Returning empty results
```golang
mockedHTTPClient := NewMockedHTTPClient(
WithRequestMatch(
GetReposIssuesByOwnerByRepo,
[]github.Issue{
{
ID: github.Int64(123),
Title: github.String("Issue 1"),
},
{
ID: github.Int64(456),
Title: github.String("Issue 2"),
},
},
[]github.Issue{},
),
)c := github.NewClient(mockedHTTPClient)
ctx := context.Background()
issues1, _, repo1Err := c.Issues.ListByRepo(ctx, "owner1", "repo1", &github.IssueListByRepoOptions{})
// len(issues1) == 2
// repo1Err == nilissues2, _, repo2Err := c.Issues.ListByRepo(ctx, "owner1", "repo2", &github.IssueListByRepoOptions{})
// len(issues2) == 0
// repo2Err == nil
```### Mocking errors from the API
```golang
mockedHTTPClient := mock.NewMockedHTTPClient(
mock.WithRequestMatchHandler(
mock.GetUsersByUsername,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mock.WriteError(
w,
http.StatusInternalServerError,
"github went belly up or something",
)
}),
),
)
c := github.NewClient(mockedHTTPClient)ctx := context.Background()
user, _, userErr := c.Users.Get(ctx, "someUser")
// user == nil
if userErr == nil {
if ghErr, ok := userErr.(*github.ErrorResponse); ok {
fmt.Println(ghErr.Message) // == "github went belly up or something"
}
}```
### Mocking with pagination
```golang
mockedHTTPClient := NewMockedHTTPClient(
WithRequestMatchPages(
GetOrgsReposByOrg,
[]github.Repository{
{
Name: github.String("repo-A-on-first-page"),
},
{
Name: github.String("repo-B-on-first-page"),
},
},
[]github.Repository{
{
Name: github.String("repo-C-on-second-page"),
},
{
Name: github.String("repo-D-on-second-page"),
},
},
),
)c := github.NewClient(mockedHTTPClient)
ctx := context.Background()
opt := &github.RepositoryListByOrgOptions{
ListOptions: github.ListOptions{
// in fact, the perPage option is ignored my the mocks
// but this would be present in production code
PerPage: 2,
},
}var allRepos []*github.Repository
for {
repos, resp, listErr := c.Repositories.ListByOrg(ctx, "foobar", opt)if listErr != nil {
t.Errorf("error listing repositories: %s", listErr.Error())
}// len(repos) == 2
allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}opt.Page = resp.NextPage
}// matches the mock definitions len(page[0]) + len(page[1])
// len(allRepos) == 4
```### Mocking for GitHub Enterprise
Github Enterprise uses a different prefix for its endpoints. In order to use the correct endpoints, please use the different set of `*Enterprise` options:
- WithRequestMatchEnterprise
- WithRequestMatchPagesEnterprise```golang
mockedHTTPClient := mock.NewMockedHTTPClient(
mock.WithRequestMatchEnterprise( // uses enterprise endpoints instead
mock.GetUsersByUsername,
github.User{
Name: github.String("foobar"),
},
),
)c := githubEnterprise.NewClient(mockedHTTPClient)
ctx := context.Background()
user, _, userErr := c.Users.Get(ctx, "myuser")
// user.Name == "foobar"
```### Mocking with rate limits
`WithRateLimit` uses a single rate-limiting middleware across all endpoints on the mock router.
**NOTE:** This is an alpha feature. Future changes might break compatibility, until a stable version is released.
```go
mockedHTTPClient := mock.NewMockedHTTPClient(
mock.WithRequestMatchPages(
mock.GetOrgsReposByOrg,
[]github.Repository{{Name: github.String(repoOne)}},
[]github.Repository{{Name: github.String(repoTwo)}},
),// The rate limiter will allow 10 requests per second, and a burst size of 1.
// These two options together mean that the rate of requests will be strictly enforced, so if any two requests are
// made less than 1/10th of a second apart, the latter will be refused and come back with a rate limit error.
mock.WithRateLimit(10, 1),
)
```## Why
Some conversations got started on [go-github#1800](https://github.com/google/go-github/issues/1800) since `go-github` didn't provide an interface that could be easily reimplemented for unittests. After lots of conversations from the folks from [go-github](https://github.com/google/go-github) and quite a few PR ideas later, this style of testing was deemed not suitable to be part of the core SDK as it's not a feature of the API itself. Nonetheless, the ability of writing unittests for code that uses the `go-github` package is critical.
A reuseable, and not overly verbose, way of writing the tests was reached after some more interactions (months down the line) and here we are.
## Thanks
Thanks for all ideas and feedback from the folks in [go-github](https://github.com/google/go-github/).
## License
This library is distributed under the MIT License found in LICENSE.