This is the client SDK for the Keploy testing platform. You can use this to generate realistic mock/stub files for your applications.
go get -u github.com/keploy/go-sdk/v2
The code coverage for the keploy API tests using the go-test
integration.
Keploy can be integrated in your CI pipeline which can add the coverage of your keploy test.
These mocks/stubs are realistic and frees you up from writing them manually. Keploy creates readable/editable
mocks/stubs yaml files which can be referenced in any of your unit-tests tests. An example is mentioned in Mocking/Stubbing for unit tests section
- Install keploy binary
- Record: To record you can import the keploy mocking library and set the mode to record mode and run you databases. This should generate a file containing the mocks/stubs.
import(
"github.com/keploy/go-sdk/v2/keploy"
)
// Inside your unit test
...
err := keploy.New(keploy.Config{
Mode: keploy.MODE_RECORD, // It can be MODE_TEST or MODE_OFF. Default is MODE_TEST. Default MODE_TEST
Name: "<stub_name/mock_name>" // TestSuite name to record the mock or test the mocks
Path: "<local_path_for_saving_mock>", // optional. It can be relative(./internals) or absolute(/users/xyz/...)
MuteKeployLogs: false, // optional. It can be true or false. If it is true keploy logs will be not shown in the unit test terminal. Default: false
delay: 10, // by default it is 5 . This delay is for running keploy
})
...
At the end of the test case you can add the following function which will terminate keploy if not keploy will be running even after unit test is run
keploy.KillProcessOnPort()
- Mock: To mock dependency as per the content of the generated file (during testing) - just set the
Mode
config tokeploy.MODE_TEST
eg:
err := keploy.New(keploy.Config{
Mode: keploy.MODE_TEST,
Name: "<stub_name/mock_name>"
Path: "<local_path_for_saving_mock>",
MubeKeployLogs: false,
delay: 10,
})
Mocks/Stubs can be generated for external dependency calls of go unit tests as readable/editable
yaml files using Keploy.
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/keploy/go-sdk/v2/keploy"
)
func setup(t *testing.T) {
err := keploy.New(keploy.Config{
Name: "TestPutURL",
Mode: keploy.MODE_RECORD, // change to MODE_TEST when you run in test mode
Path: "/home/ubuntu/dont_touch/samples-go/gin-mongo",
MuteKeployLogs: false,
Delay: 15,
})
if err != nil {
t.Fatalf("error while running keploy: %v", err)
}
dbName, collection := "keploy", "url-shortener"
client, err := New("localhost:27017", dbName)
if err != nil {
panic("Failed to initialize MongoDB: " + err.Error())
}
db := client.Database(dbName)
col = db.Collection(collection)
}
func TestPutURL(t *testing.T) {
defer keploy.KillProcessOnPort()
setup(t)
r := gin.Default()
r.GET("/:param", getURL)
r.POST("/url", putURL)
data := map[string]string{
"url": "https://www.example.com",
}
payload, err := json.Marshal(data)
if err != nil {
t.Fatalf("rfe: %v\n", err)
}
req, err := http.NewRequest(http.MethodPost, "/url", bytes.NewBuffer(payload))
if err != nil {
t.Fatalf("Couldn't create request: %v\n", err)
}
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
// Checking if the URL was successfully shortened and stored
if w.Code != http.StatusOK {
t.Fatalf("Expected HTTP 200 OK, but got %v", w.Code)
}
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
if err != nil {
t.Fatalf("Failed to unmarshal response: %v\n", err)
}
fmt.Println("response-url" + response["url"].(string))
if response["url"] == nil || response["ts"] == nil {
t.Fatalf("Response did not contain expected fields")
}
}
The percentage of code covered by the recorded tests is logged if the test cmd is ran with the go binary and withCoverage
flag. The conditions for the coverage is:
- The go binary should be built with
-cover
flag. - The application should have a graceful shutdown to stop the API server on
SIGTERM
orSIGINT
signals. Or if not call the GracefulShutdown from the main function of your go program. Ex:
func main() {
port := "8080"
r := gin.Default()
r.GET("/:param", getURL)
r.POST("/url", putURL)
// should be called before starting the API server from main()
keploy.GracefulShutdown()
r.Run()
}
The keploy test cmd will look like:
keploy test -c "PATH_TO_GO_COVER_BIANRY" --withCoverage
The coverage files will be stored in the directory.
keploy
βββ coverage-reports
β βββ covcounters.befc2fe88a620bbd45d85aa09517b5e7.305756.1701767439933176870
β βββ covmeta.befc2fe88a620bbd45d85aa09517b5e7
β βββ total-coverage.txt
βββ test-set-0
β βββ mocks.yaml
β βββ tests
β βββ test-1.yaml
β βββ test-2.yaml
β βββ test-3.yaml
β βββ test-4.yaml
Coverage percentage log in the cmd will be:
π° Keploy: 2023-12-07T08:53:14Z INFO test/test.go:261
test-app-url-shortener coverage: 78.4% of statements
Also the go-test coverage can be merged along the recorded tests coverage by following the steps:
go test -cover ./... -args -test.gocoverdir="PATH_TO_UNIT_COVERAGE_FILES"
go tool covdata textfmt -i="PATH_TO_UNIT_COVERAGE_FILES","./keploy/coverage-reports" -o coverage-profile
go tool cover -func coverage-profile