{"id":28724146,"url":"https://github.com/processone/httpmock","last_synced_at":"2025-08-18T04:09:25.725Z","repository":{"id":136894921,"uuid":"168958575","full_name":"processone/httpmock","owner":"processone","description":"HTTP recorder and mock library","archived":false,"fork":false,"pushed_at":"2019-03-09T16:04:27.000Z","size":692,"stargazers_count":9,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-15T10:09:20.852Z","etag":null,"topics":["go","golang","http","testing"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/processone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-03T15:14:09.000Z","updated_at":"2022-04-14T06:15:30.000Z","dependencies_parsed_at":"2023-04-14T01:31:25.872Z","dependency_job_id":null,"html_url":"https://github.com/processone/httpmock","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/processone/httpmock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fhttpmock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fhttpmock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fhttpmock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fhttpmock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/processone","download_url":"https://codeload.github.com/processone/httpmock/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fhttpmock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270940950,"owners_count":24671743,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-18T02:00:08.743Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","http","testing"],"created_at":"2025-06-15T10:09:19.844Z","updated_at":"2025-08-18T04:09:25.694Z","avatar_url":"https://github.com/processone.png","language":"HTML","readme":"# HTTPMock\n\n[![Codeship Status for processone/httpmock](https://app.codeship.com/projects/cf2e6700-1b1a-0137-02c9-72d9af1082b6/status?branch=master)](https://app.codeship.com/projects/328623)\n\nIf you need to write tests for code involving lot of API and web page scrapping, you often end up saving pages as\nfixtures and loading those fixtures to try injecting them in your code to simulate the query.\n\nHowever, it is time consuming to manage your test scenario and difficult to mock the HTTP calls as they can be done\nvery deep in your code.\n\nThis HTTPMock library intend to make those HTTP requests heavy test easier by allowing to record HTTP scenarii and\nreplay them easily in your tests.\n\n## Overview\n\nHTTPMock is composed of:\n\n- a Go HTTP Mock library for writing tests,\n- an HTTP scenario recording tool.\n\nThis library is used to record scenario that can be replayed locally, exactly as recorded.\nIt is helpful to prepare tests for your Go code when there is underlying HTTP requests. You can thus be sure\nthe test will replay real traffic consistently. Those recorded tests are also useful to document the behaviour \nof your code against a specific version of API or content. When the target HTTP endpoint changes and breaks your\ncode, you can thus now easily generate a diff of the HTTP content to understand the change in behaviour and\nadapt your code accordingly.\n\n## Usage\n\n### Tutorial\n\nA video tutorial is available: [CodeCraft #1: Writing tests in Go with HTTPMock](https://vimeo.com/321310857)\n\n### Recording scenario\n\nRecording a scenario is done by adding URL endpoint your want to support.\n\nWhen you add an endpoint to a scenario, the instrument HTTP client will be able to reply properly with the recorded\ndata.\n\nThe recorder stores:\n\n- Replies to that request, including header and body;\n- Redirect sequence if any. This is important to exercice some behaviour in your HTTP crawler code.\n\nYou can install HTTP recorder with the following command:\n\n```bash\ngo get -u gosrc.io/httpmock/httprec\n```\n\nTo create a scenario file in your fixtures directory, you can then use the following command:\n\n```bash\nhttprec add fixtures/scenario1 -u https://www.process-one.net/\n```\n\n### Using the scenario in a test case\n\nTo use the scenario in a test case, you need to:\n\n- Create an HTTPMock instance\n- Load the scenario you would like to use (set of endpoints and replies)\n- Pass the HTTPClient provided by HTTPMock to your code / library so that replies received by your code will be\n  the one from the scenario.\n\nFor example:\n\n```go\npackage httpmock_test\n\nimport (\n\t\"bytes\"\n\t\"io/ioutil\"\n\t\"testing\"\n\n\t\"gosrc.io/httpmock\"\n)\n\nfunc TestHTTPMock(t *testing.T) {\n\t// Setup HTTP Mock\n\tmock := httpmock.NewMock(\"fixtures/\")\n\n\t// Scenario generated with:\n\t// httprec add fixtures/ProcessOne -u https://www.process-one.net/\n\tfixtureName := \"ProcessOne\"\n\tif err := mock.LoadScenario(fixtureName); err != nil {\n\t\tt.Errorf(\"Cannot load fixture scenario %s: %s\", fixtureName, err)\n\t\treturn\n\t}\n\n\tHTTPClient := mock.Client\n\tresp, err := HTTPClient.Get(\"https://www.process-one.net/\")\n\tif err != nil {\n\t\tt.Errorf(\"Cannot get page: %s\", err)\n\t\treturn\n\t}\n\tdefer resp.Body.Close()\n\n\tcontent, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\tt.Errorf(\"Cannot read page body: %s\", err)\n\t\treturn\n\t}\n\tif bytes.Contains(content, []byte(\"ProcessOne\")) == false {\n\t\tt.Errorf(\"'ProcessOne' not found on page\")\n\t}\n}\n```\n\n### Writing custom HTTP mocks\n\nYou can configure HTTP mocks to reply with custom data that does not come from a scenario.\n\nHere is an example on how to use this feature. In this example, we test that we can follow redirect and return the\nfinal of a sequence. This can be used to check that we can properly resolve short URLs:\n\n```go\npackage httpmock_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"gosrc.io/httpmock\"\n\n\t\"github.com/processone/dpk/pkg/semweb\"\n)\n\nfunc TestFollowRedirect(t *testing.T) {\n\ttargetSite := \"https://process-one.net\"\n\tresponder := func(req *http.Request) (*http.Response, error) {\n\t\tif req.URL.Host == \"t.co\" {\n\t\t\tresp := RedirectResponse(targetSite)\n\t\t\tresp.Request = req\n\t\t\treturn resp, nil\n\t\t}\n\t\tif req.URL.Host == \"process-one.net\" {\n\t\t\tresp := SimplePageResponse(\"Target Page Title\")\n\t\t\tresp.Request = req\n\t\t\treturn resp, nil\n\t\t}\n\t\tt.Errorf(\"unknown host: %s\", req.Host)\n\t\treturn nil, errors.New(\"unknown host\")\n\t}\n\n\tmock := httpmock.NewMock(\"\")\n\tmock.SetResponder(responder)\n\tc := semweb.NewClient()\n\tc.HTTPClient = mock.Client\n\turi := c.FollowRedirect(\"https://t.co/shortURL\")\n\tif uri != targetSite {\n\t\tt.Errorf(\"unexpected uri: %s\", uri)\n\t}\n}\n\n// Simple basic HTTP responses\n\nfunc RedirectResponse(location string) *http.Response {\n\tstatus := 301\n\treader := bytes.NewReader([]byte{})\n\theader := http.Header{}\n\theader.Add(\"Location\", location)\n\tresponse := http.Response{\n\t\tStatus:     strconv.Itoa(status),\n\t\tStatusCode: status,\n\t\tBody:       ioutil.NopCloser(reader),\n\t\tHeader:     header,\n\t}\n\treturn \u0026response\n}\n\nfunc SimplePageResponse(title string) *http.Response {\n\tstatus := 200\n\ttemplate := `\u003chtml\u003e\n\u003chead\u003e\u003ctitle\u003e%s\u003c/title\u003e\u003c/head\u003e\n\u003cbody\u003e\u003ch2\u003e%s\u003c/h2\u003e\u003c/body\u003e\n\u003c/html\u003e`\n\tpage := fmt.Sprintf(template, title, title)\n\treader := strings.NewReader(page)\n\tresponse := http.Response{\n\t\tStatus:     strconv.Itoa(status),\n\t\tStatusCode: status,\n\t\tBody:       ioutil.NopCloser(reader),\n\t\tHeader:     http.Header{},\n\t}\n\treturn \u0026response\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprocessone%2Fhttpmock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprocessone%2Fhttpmock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprocessone%2Fhttpmock/lists"}