generated from keploy/template
-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add utg guide in mux-sql (#107)
Signed-off-by: Animesh Pathak <[email protected]>
- Loading branch information
Showing
4 changed files
with
163 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,6 @@ curl --silent -O -L https://keploy.io/install.sh && source install.sh | |
Using the docker-compose file we will start our postgres instance:- | ||
|
||
```bash | ||
# Start Postgres | ||
docker-compose up -d postgres | ||
``` | ||
|
||
|
@@ -48,7 +47,7 @@ Make API Calls using Hoppscotch, Postman or cURL command. Keploy with capture th | |
|
||
To genereate testcases we just need to make some API calls. You can use [Postman](https://www.postman.com/), [Hoppscotch](https://hoppscotch.io/), or simply `curl` | ||
|
||
### 1. Generate shortned url | ||
1. Generate shortned url | ||
|
||
```bash | ||
curl --request POST \ | ||
|
@@ -68,7 +67,7 @@ this will return the response. | |
} | ||
``` | ||
|
||
### 2. Fetch the Products | ||
2. Fetch the Products | ||
```bash | ||
curl --request GET \ | ||
--url http://localhost:8010/products | ||
|
@@ -80,7 +79,7 @@ we will get output: | |
[{"id":1,"name":"Bubbles","price":123},{"id":2,"name":"Bubbles","price":123}] | ||
``` | ||
|
||
### 3. Fetch a single product | ||
3. Fetch a single product | ||
|
||
```sh | ||
curl --request GET \ | ||
|
@@ -97,6 +96,8 @@ Now, since these API calls were captured as editable testcases and written to `` | |
|
||
Now let's run the test mode (in the mux-sql directory, not the Keploy directory). | ||
### Run captured testcases | ||
```shell | ||
sudo -E keploy test -c "./test-app-product-catelog" --delay 10 --goCoverage | ||
``` | ||
|
@@ -109,4 +110,48 @@ So no need to setup fake database/apis like Postgres or write mocks for them. Ke | |
|
||
With the three API calls that we made, we got around `55.6%` of coverage | ||
|
||
![test coverage](./img/coverage.png?raw=true) | ||
![test coverage](./img/coverage.png?raw=true) | ||
|
||
## Create Unit Testcase with Keploy | ||
|
||
### Prequiste | ||
AI model API_KEY to use: | ||
|
||
- OpenAI's GPT-4o. | ||
- Alternative LLMs via [litellm](https://github.com/BerriAI/litellm?tab=readme-ov-file#quick-start-proxy---cli). | ||
### Setup | ||
Download Cobertura formatted coverage report dependencies. | ||
```bash | ||
go install github.com/axw/gocov/[email protected] | ||
go install github.com/AlekSi/[email protected] | ||
``` | ||
Get API key from [OpenAI](https://platform.openai.com/) or API Key from other LLM | ||
```bash | ||
export API_KEY=<LLM_MODEL_API_KEY> | ||
``` | ||
### Generate Unit tests | ||
Let's check the current code coverage of out application : - | ||
|
||
```bash | ||
go test -v ./... -coverprofile=coverage.out && gocov convert coverage.out | gocov-xml > coverage.xml | ||
``` | ||
We got around 44.1% of code coverage. | ||
|
||
![Go Test](./img/mux-utg.png?raw=true) | ||
|
||
Now, let's run create keploy to create testcases. | ||
```bash | ||
keploy gen --sourceFilePath="app.go" --testFilePath="app_test.go" --testCommand="go test -v ./... -coverprofile=coverage.out && gocov convert coverage.out | gocov-xml > coverage.xml" --coverageReportPath="./coverage.xml" --expectedCoverage 70 --maxIterations 2 | ||
``` | ||
With the above command, Keploy will generate new testcases in the our `app_test.go` can increase code coverage upto 70%. | ||
![Keploy Mux UTG](./img/mux-utg-codecov.png?raw=true) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package main_test | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"log" | ||
"net/http" | ||
"net/http/httptest" | ||
"os" | ||
"testing" | ||
"test-app-product-catelog" | ||
) | ||
|
||
var a main.App | ||
|
||
func TestMain(m *testing.M) { | ||
a.Initialize( | ||
"localhost", "postgres", "password", | ||
"postgres") | ||
ensureTableExists() | ||
code := m.Run() | ||
clearTable() | ||
os.Exit(code) | ||
} | ||
|
||
func ensureTableExists() { | ||
if _, err := a.DB.Exec(tableCreationQuery); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func clearTable() { | ||
a.DB.Exec("DELETE FROM products") | ||
a.DB.Exec("ALTER SEQUENCE products_id_seq RESTART WITH 1") | ||
} | ||
|
||
const tableCreationQuery = `CREATE TABLE IF NOT EXISTS products | ||
( | ||
id SERIAL, | ||
name TEXT NOT NULL, | ||
price NUMERIC(10,2) NOT NULL DEFAULT 0.00, | ||
CONSTRAINT products_pkey PRIMARY KEY (id) | ||
)` | ||
|
||
func TestEmptyTable(t *testing.T) { | ||
clearTable() | ||
|
||
req, _ := http.NewRequest("GET", "/products", nil) | ||
response := executeRequest(req) | ||
|
||
checkResponseCode(t, http.StatusOK, response.Code) | ||
|
||
if body := response.Body.String(); body != "[]" { | ||
t.Errorf("Expected an empty array. Got %s", body) | ||
} | ||
} | ||
|
||
func executeRequest(req *http.Request) *httptest.ResponseRecorder { | ||
rr := httptest.NewRecorder() | ||
a.Router.ServeHTTP(rr, req) | ||
|
||
return rr | ||
} | ||
|
||
func checkResponseCode(t *testing.T, expected, actual int) { | ||
if expected != actual { | ||
t.Errorf("Expected response code %d. Got %d\n", expected, actual) | ||
} | ||
} | ||
|
||
func TestGetNonExistentProduct(t *testing.T) { | ||
clearTable() | ||
|
||
req, _ := http.NewRequest("GET", "/product/11", nil) | ||
response := executeRequest(req) | ||
|
||
checkResponseCode(t, http.StatusNotFound, response.Code) | ||
|
||
var m map[string]string | ||
json.Unmarshal(response.Body.Bytes(), &m) | ||
if m["error"] != "Product not found" { | ||
t.Errorf("Expected the 'error' key of the response to be set to 'Product not found'. Got '%s'", m["error"]) | ||
} | ||
} | ||
|
||
func TestCreateProduct(t *testing.T) { | ||
|
||
clearTable() | ||
|
||
var jsonStr = []byte(`{"name":"test product", "price": 11.22}`) | ||
req, _ := http.NewRequest("POST", "/product", bytes.NewBuffer(jsonStr)) | ||
req.Header.Set("Content-Type", "application/json") | ||
|
||
response := executeRequest(req) | ||
checkResponseCode(t, http.StatusCreated, response.Code) | ||
|
||
var m map[string]interface{} | ||
json.Unmarshal(response.Body.Bytes(), &m) | ||
|
||
if m["name"] != "test product" { | ||
t.Errorf("Expected product name to be 'test product'. Got '%v'", m["name"]) | ||
} | ||
|
||
if m["price"] != 11.22 { | ||
t.Errorf("Expected product price to be '11.22'. Got '%v'", m["price"]) | ||
} | ||
|
||
// the id is compared to 1.0 because JSON unmarshaling converts numbers to | ||
// floats, when the target is a map[string]interface{} | ||
if m["id"] != 1.0 { | ||
t.Errorf("Expected product ID to be '1'. Got '%v'", m["id"]) | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.