feat: support output the test report (#17)
Co-authored-by: rick <LinuxSuRen@users.noreply.github.com>
This commit is contained in:
parent
4a4554d53b
commit
078d4c861b
|
@ -0,0 +1,5 @@
|
||||||
|
Print the code of lines:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git ls-files | xargs cloc
|
||||||
|
```
|
2
Makefile
2
Makefile
|
@ -6,4 +6,4 @@ build:
|
||||||
copy: build
|
copy: build
|
||||||
sudo cp bin/atest /usr/local/bin/
|
sudo cp bin/atest /usr/local/bin/
|
||||||
test:
|
test:
|
||||||
go test ./...
|
go test ./... -cover
|
||||||
|
|
47
cmd/run.go
47
cmd/run.go
|
@ -3,6 +3,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -28,18 +29,36 @@ type runOption struct {
|
||||||
burst int32
|
burst int32
|
||||||
limiter limit.RateLimiter
|
limiter limit.RateLimiter
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
|
reporter runner.TestReporter
|
||||||
|
reportWriter runner.ReportResultWriter
|
||||||
|
report string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultRunOption() *runOption {
|
||||||
|
return &runOption{
|
||||||
|
reporter: runner.NewmemoryTestReporter(),
|
||||||
|
reportWriter: runner.NewResultWriter(os.Stdout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDiskCardRunOption() *runOption {
|
||||||
|
return &runOption{
|
||||||
|
reporter: runner.NewDiscardTestReporter(),
|
||||||
|
reportWriter: runner.NewDiscardResultWriter(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRunCommand returns the run command
|
// CreateRunCommand returns the run command
|
||||||
func CreateRunCommand() (cmd *cobra.Command) {
|
func CreateRunCommand() (cmd *cobra.Command) {
|
||||||
opt := &runOption{}
|
opt := newDefaultRunOption()
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "run",
|
Use: "run",
|
||||||
Aliases: []string{"r"},
|
Aliases: []string{"r"},
|
||||||
Example: `atest run -p sample.yaml
|
Example: `atest run -p sample.yaml
|
||||||
See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
|
See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
|
||||||
Short: "Run the test suite",
|
Short: "Run the test suite",
|
||||||
RunE: opt.runE,
|
PreRunE: opt.preRunE,
|
||||||
|
RunE: opt.runE,
|
||||||
}
|
}
|
||||||
|
|
||||||
// set flags
|
// set flags
|
||||||
|
@ -52,6 +71,15 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
|
||||||
flags.Int64VarP(&opt.thread, "thread", "", 1, "Threads of the execution")
|
flags.Int64VarP(&opt.thread, "thread", "", 1, "Threads of the execution")
|
||||||
flags.Int32VarP(&opt.qps, "qps", "", 5, "QPS")
|
flags.Int32VarP(&opt.qps, "qps", "", 5, "QPS")
|
||||||
flags.Int32VarP(&opt.burst, "burst", "", 5, "burst")
|
flags.Int32VarP(&opt.burst, "burst", "", 5, "burst")
|
||||||
|
flags.StringVarP(&opt.report, "report", "", "", "The type of target report")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *runOption) preRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
switch o.report {
|
||||||
|
case "markdown", "md":
|
||||||
|
o.reportWriter = runner.NewMarkdownResultWriter(cmd.OutOrStdout())
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +101,14 @@ func (o *runOption) runE(cmd *cobra.Command, args []string) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print the report
|
||||||
|
if err == nil {
|
||||||
|
var results []runner.ReportResult
|
||||||
|
if results, err = o.reporter.ExportAllReportResults(); err == nil {
|
||||||
|
err = o.reportWriter.Output(results)
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +201,10 @@ func (o *runOption) runSuite(suite string, dataContext map[string]interface{}, c
|
||||||
o.limiter.Accept()
|
o.limiter.Accept()
|
||||||
|
|
||||||
ctxWithTimeout, _ := context.WithTimeout(ctx, o.requestTimeout)
|
ctxWithTimeout, _ := context.WithTimeout(ctx, o.requestTimeout)
|
||||||
if output, err = runner.RunTestCase(&testCase, dataContext, ctxWithTimeout); err != nil && !o.requestIgnoreError {
|
|
||||||
|
simpleRunner := runner.NewSimpleTestCaseRunner()
|
||||||
|
simpleRunner.WithTestReporter(o.reporter)
|
||||||
|
if output, err = simpleRunner.RunTestCase(&testCase, dataContext, ctxWithTimeout); err != nil && !o.requestIgnoreError {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,9 @@ func TestRunSuite(t *testing.T) {
|
||||||
|
|
||||||
tt.prepare()
|
tt.prepare()
|
||||||
ctx := getDefaultContext()
|
ctx := getDefaultContext()
|
||||||
opt := &runOption{
|
opt := newDiskCardRunOption()
|
||||||
requestTimeout: 30 * time.Second,
|
opt.requestTimeout = 30 * time.Second
|
||||||
limiter: limit.NewDefaultRateLimiter(0, 0),
|
opt.limiter = limit.NewDefaultRateLimiter(0, 0)
|
||||||
}
|
|
||||||
stopSingal := make(chan struct{}, 1)
|
stopSingal := make(chan struct{}, 1)
|
||||||
|
|
||||||
err := opt.runSuite(tt.suiteFile, ctx, context.TODO(), stopSingal)
|
err := opt.runSuite(tt.suiteFile, ctx, context.TODO(), stopSingal)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
| API | Average | Max | Min | Count | Error |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
{{- range $val := .}}
|
||||||
|
| {{$val.API}} | {{$val.Average}} | {{$val.Max}} | {{$val.Min}} | {{$val.Count}} | {{$val.Error}} |
|
||||||
|
{{- end}}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package runner
|
||||||
|
|
||||||
|
type discardTestReporter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiscardTestReporter creates a test reporter which discard everything
|
||||||
|
func NewDiscardTestReporter() TestReporter {
|
||||||
|
return &discardTestReporter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *discardTestReporter) PutRecord(*ReportRecord) {}
|
||||||
|
func (r *discardTestReporter) GetAllRecords() []*ReportRecord {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (r *discardTestReporter) ExportAllReportResults() (ReportResultSlice, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package runner_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/linuxsuren/api-testing/pkg/runner"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDiscardTestReporter(t *testing.T) {
|
||||||
|
reporter := runner.NewDiscardTestReporter()
|
||||||
|
assert.NotNil(t, reporter)
|
||||||
|
assert.Nil(t, reporter.GetAllRecords())
|
||||||
|
|
||||||
|
result, err := reporter.ExportAllReportResults()
|
||||||
|
assert.Nil(t, result)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
reporter.PutRecord(&runner.ReportRecord{})
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package runner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type memoryTestReporter struct {
|
||||||
|
records []*ReportRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewmemoryTestReporter creates a memory based test reporter
|
||||||
|
func NewmemoryTestReporter() TestReporter {
|
||||||
|
return &memoryTestReporter{
|
||||||
|
records: []*ReportRecord{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportResultWithTotal struct {
|
||||||
|
ReportResult
|
||||||
|
Total time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *memoryTestReporter) PutRecord(record *ReportRecord) {
|
||||||
|
r.records = append(r.records, record)
|
||||||
|
}
|
||||||
|
func (r *memoryTestReporter) GetAllRecords() []*ReportRecord {
|
||||||
|
return r.records
|
||||||
|
}
|
||||||
|
func (r *memoryTestReporter) ExportAllReportResults() (result ReportResultSlice, err error) {
|
||||||
|
resultWithTotal := map[string]*ReportResultWithTotal{}
|
||||||
|
for _, record := range r.records {
|
||||||
|
api := record.Method + " " + record.API
|
||||||
|
duration := record.Duration()
|
||||||
|
|
||||||
|
if item, ok := resultWithTotal[api]; ok {
|
||||||
|
if item.Max < duration {
|
||||||
|
item.Max = duration
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Min > duration {
|
||||||
|
item.Min = duration
|
||||||
|
}
|
||||||
|
item.Error += record.ErrorCount()
|
||||||
|
item.Total += duration
|
||||||
|
item.Count += 1
|
||||||
|
} else {
|
||||||
|
resultWithTotal[api] = &ReportResultWithTotal{
|
||||||
|
ReportResult: ReportResult{
|
||||||
|
API: api,
|
||||||
|
Count: 1,
|
||||||
|
Max: duration,
|
||||||
|
Min: duration,
|
||||||
|
Error: record.ErrorCount(),
|
||||||
|
},
|
||||||
|
Total: duration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range resultWithTotal {
|
||||||
|
r.Average = r.Total / time.Duration(r.Count)
|
||||||
|
result = append(result, r.ReportResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(result)
|
||||||
|
return
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/andreyvit/diff"
|
"github.com/andreyvit/diff"
|
||||||
"github.com/antonmedv/expr"
|
"github.com/antonmedv/expr"
|
||||||
|
@ -21,9 +22,94 @@ import (
|
||||||
unstructured "github.com/linuxsuren/unstructured/pkg"
|
unstructured "github.com/linuxsuren/unstructured/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunTestCase runs the test case
|
type TestCaseRunner interface {
|
||||||
func RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) {
|
RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error)
|
||||||
fmt.Printf("start to run: '%s'\n", testcase.Name)
|
WithOutputWriter(io.Writer) TestCaseRunner
|
||||||
|
WithTestReporter(TestReporter) TestCaseRunner
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportRecord struct {
|
||||||
|
Method string
|
||||||
|
API string
|
||||||
|
BeginTime time.Time
|
||||||
|
EndTime time.Time
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration returns the duration between begin and end time
|
||||||
|
func (r *ReportRecord) Duration() time.Duration {
|
||||||
|
return r.EndTime.Sub(r.BeginTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReportRecord) ErrorCount() int {
|
||||||
|
if r.Error == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReportRecord creates a record, and set the begin time to be now
|
||||||
|
func NewReportRecord() *ReportRecord {
|
||||||
|
return &ReportRecord{
|
||||||
|
BeginTime: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportResult struct {
|
||||||
|
API string
|
||||||
|
Count int
|
||||||
|
Average time.Duration
|
||||||
|
Max time.Duration
|
||||||
|
Min time.Duration
|
||||||
|
Error int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportResultSlice []ReportResult
|
||||||
|
|
||||||
|
func (r ReportResultSlice) Len() int {
|
||||||
|
return len(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ReportResultSlice) Less(i, j int) bool {
|
||||||
|
return r[i].Average > r[j].Average
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ReportResultSlice) Swap(i, j int) {
|
||||||
|
tmp := r[i]
|
||||||
|
r[i] = r[j]
|
||||||
|
r[j] = tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportResultWriter interface {
|
||||||
|
Output([]ReportResult) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestReporter interface {
|
||||||
|
PutRecord(*ReportRecord)
|
||||||
|
GetAllRecords() []*ReportRecord
|
||||||
|
ExportAllReportResults() (ReportResultSlice, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type simpleTestCaseRunner struct {
|
||||||
|
testReporter TestReporter
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSimpleTestCaseRunner creates the instance of the simple test case runner
|
||||||
|
func NewSimpleTestCaseRunner() TestCaseRunner {
|
||||||
|
runner := &simpleTestCaseRunner{}
|
||||||
|
return runner.WithOutputWriter(io.Discard).WithTestReporter(NewDiscardTestReporter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) {
|
||||||
|
fmt.Fprintf(r.writer, "start to run: '%s'\n", testcase.Name)
|
||||||
|
record := NewReportRecord()
|
||||||
|
defer func(rr *ReportRecord) {
|
||||||
|
rr.EndTime = time.Now()
|
||||||
|
rr.Error = err
|
||||||
|
r.testReporter.PutRecord(rr)
|
||||||
|
}(record)
|
||||||
|
|
||||||
if err = doPrepare(testcase); err != nil {
|
if err = doPrepare(testcase); err != nil {
|
||||||
err = fmt.Errorf("failed to prepare, error: %v", err)
|
err = fmt.Errorf("failed to prepare, error: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -77,13 +163,15 @@ func RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx contex
|
||||||
if request, err = http.NewRequestWithContext(ctx, testcase.Request.Method, testcase.Request.API, requestBody); err != nil {
|
if request, err = http.NewRequestWithContext(ctx, testcase.Request.Method, testcase.Request.API, requestBody); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
record.API = testcase.Request.API
|
||||||
|
record.Method = testcase.Request.Method
|
||||||
|
|
||||||
// set headers
|
// set headers
|
||||||
for key, val := range testcase.Request.Header {
|
for key, val := range testcase.Request.Header {
|
||||||
request.Header.Add(key, val)
|
request.Header.Add(key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("start to send request to", testcase.Request.API)
|
fmt.Fprintf(r.writer, "start to send request to %s\n", testcase.Request.API)
|
||||||
|
|
||||||
// send the HTTP request
|
// send the HTTP request
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
|
@ -178,6 +266,22 @@ func RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx contex
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *simpleTestCaseRunner) WithOutputWriter(writer io.Writer) TestCaseRunner {
|
||||||
|
r.writer = writer
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *simpleTestCaseRunner) WithTestReporter(reporter TestReporter) TestCaseRunner {
|
||||||
|
r.testReporter = reporter
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
|
// RunTestCase runs the test case.
|
||||||
|
func RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) {
|
||||||
|
return NewSimpleTestCaseRunner().WithOutputWriter(os.Stdout).RunTestCase(testcase, dataContext, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func doPrepare(testcase *testing.TestCase) (err error) {
|
func doPrepare(testcase *testing.TestCase) (err error) {
|
||||||
for i := range testcase.Prepare.Kubernetes {
|
for i := range testcase.Prepare.Kubernetes {
|
||||||
item := testcase.Prepare.Kubernetes[i]
|
item := testcase.Prepare.Kubernetes[i]
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package runner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stdResultWriter struct {
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResultWriter(writer io.Writer) ReportResultWriter {
|
||||||
|
return &stdResultWriter{writer: writer}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiscardResultWriter creates a report result writer which discard everything
|
||||||
|
func NewDiscardResultWriter() ReportResultWriter {
|
||||||
|
return &stdResultWriter{writer: io.Discard}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *stdResultWriter) Output(result []ReportResult) error {
|
||||||
|
fmt.Fprintf(w.writer, "API Average Max Min Count Error\n")
|
||||||
|
for _, r := range result {
|
||||||
|
fmt.Fprintf(w.writer, "%s %v %v %v %d %d\n", r.API, r.Average, r.Max,
|
||||||
|
r.Min, r.Count, r.Error)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type markdownResultWriter struct {
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMarkdownResultWriter(writer io.Writer) ReportResultWriter {
|
||||||
|
if writer == nil {
|
||||||
|
writer = os.Stdout
|
||||||
|
}
|
||||||
|
return &markdownResultWriter{writer: writer}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *markdownResultWriter) Output(result []ReportResult) (err error) {
|
||||||
|
var tpl *template.Template
|
||||||
|
if tpl, err = template.New("report").Parse(markDownReport); err == nil {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
if err = tpl.Execute(buf, result); err == nil {
|
||||||
|
fmt.Fprint(w.writer, buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed data/report.md
|
||||||
|
var markDownReport string
|
|
@ -0,0 +1,80 @@
|
||||||
|
package runner_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/linuxsuren/api-testing/pkg/runner"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarkdownWriter(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
writer := runner.NewMarkdownResultWriter(buf)
|
||||||
|
|
||||||
|
err := writer.Output([]runner.ReportResult{{
|
||||||
|
API: "api",
|
||||||
|
Average: 3,
|
||||||
|
Max: 4,
|
||||||
|
Min: 2,
|
||||||
|
Count: 3,
|
||||||
|
Error: 0,
|
||||||
|
}, {
|
||||||
|
API: "api",
|
||||||
|
Average: 3,
|
||||||
|
Max: 4,
|
||||||
|
Min: 2,
|
||||||
|
Count: 3,
|
||||||
|
Error: 0,
|
||||||
|
}})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, `| API | Average | Max | Min | Count | Error |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| api | 3ns | 4ns | 2ns | 3 | 0 |
|
||||||
|
| api | 3ns | 4ns | 2ns | 3 | 0 |
|
||||||
|
`, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewStdResultWriter(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
buf *bytes.Buffer
|
||||||
|
results []runner.ReportResult
|
||||||
|
expect string
|
||||||
|
}{{
|
||||||
|
name: "result is nil",
|
||||||
|
buf: new(bytes.Buffer),
|
||||||
|
results: nil,
|
||||||
|
expect: `API Average Max Min Count Error
|
||||||
|
`,
|
||||||
|
}, {
|
||||||
|
name: "have one item",
|
||||||
|
buf: new(bytes.Buffer),
|
||||||
|
results: []runner.ReportResult{{
|
||||||
|
API: "api",
|
||||||
|
Average: 1,
|
||||||
|
Max: 1,
|
||||||
|
Min: 1,
|
||||||
|
Count: 1,
|
||||||
|
Error: 0,
|
||||||
|
}},
|
||||||
|
expect: `API Average Max Min Count Error
|
||||||
|
api 1ns 1ns 1ns 1 0
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
writer := runner.NewResultWriter(tt.buf)
|
||||||
|
if !assert.NotNil(t, writer) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := writer.Output(tt.results)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, tt.expect, tt.buf.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
discardResultWriter := runner.NewDiscardResultWriter()
|
||||||
|
assert.NotNil(t, discardResultWriter)
|
||||||
|
}
|
Loading…
Reference in New Issue