test
unit test
بخش های بسیار کوچک و فانکشن ها را با این روش تست می کنیم .
در این روش ، ورودی و خروجی و نتیجه ی فانشکن را از قبل مشخص می کنیم و تست را اجرا می کنیم .
integration test
گاهی اوقات تست به پیش نیاز هایی وابسته است ، مثلا برای تست یک ریکویست ، با وظیفه ثبت در دیتابیس یا خطا ، ما نیاز داریم که علاوه بر مشخص کردن ورودی و خروجی ، کانکتور ها ( یا dependency ها ) را هم مشخص کنیم . در این صورت می توانیم ابتدا تمامی کلاس ها یا استراکت ها را معرفی کنیم . مثلا تنظیمات کانکشن به دیتا بیس یا تنظیمات روتر .
type ParserTestSuite struct {
suite.Suite
Parser protocol.Parser
}
func (s *ParserTestSuite) SetupTest() {
parser := viper_parser.Parser{}
s.Parser = &parser
}
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, &ParserTestSuite{})
}
func (s *ParserTestSuite) TestMigration() {
conn := NewConnectionPostgres(s.Parser)
err := conn.Migration(context.Background())
s.Nil(err)
}
می توان در روت پروژه کد را زد و تمامی تست ها انجام شود :
go test -v ./...
توجه شود می توان کانفیگ را به صورت nested پیدا کرد ، در این صورت نیازی نیست در تمامی دارکتوری ها config را قرار داد .
metrics
pprof ـ portabl profile
ابتدا باید این پکیج را نصب کنیم
sudo apt install graphviz
حال باید در یک گوروتین جدا ، لیسن به کد کنیم
import (
"net/http"
_ "net/http/pprof"
)
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
- زمانی که بخواهیم مموری توی وب ببینیم
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap
- پروفایل گوروتینها:
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/goroutine
- پروفایل CPU:
و همزمان در حلقه چندین بار فانکشن هایی که احتمالا گلوگاه کد هستند را فراخانی کنیم . کد حداقل باید 30 ثانیه در حلقه تکرار شود ، همزمان کد زیر را اجرا می کنیم تا کد را از طریق ListenAndServe کد را ذخیره کند :
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30
اگر بتواند 30 ثانیه آنالیز کند ، آنگاه می توانیم به روش های گوناگون خروجی را بگیریم ولی متداول ترین روش ، وب است:
TotalAlloc
func main() {
go func() {
pkg.PrintMemStats()
}()
}
// pkg
func PrintMemStats() {
for {
var m runtime.MemStats
runtime.ReadMemStats(&m)
const mb = 1024 * 1024
timestamp := time.Now().Format(time.RFC3339)
fmt.Printf("\n---- Memory Stats at %s ----\n", timestamp)
fmt.Printf("Mallocs: %d\n", m.Mallocs)
fmt.Printf("Frees: %d\n", m.Frees)
fmt.Printf("Live Objects: %d\n", m.Mallocs-m.Frees)
fmt.Printf("TotalAlloc: %.2f MB\n", float64(m.TotalAlloc)/mb)
fmt.Printf("Alloc: %.2f MB\n", float64(m.Alloc)/mb)
fmt.Printf("HeapAlloc: %.2f MB\n", float64(m.HeapAlloc)/mb)
fmt.Printf("HeapSys: %.2f MB\n", float64(m.HeapSys)/mb)
fmt.Println("------------------------------")
time.Sleep(5 * time.Second)
}
}
pprof goroutines
گاهی شایدی تعداد زیادی گوروتین باز شده ولی استفاده نمی شه
با استفاده از pprof میشه دید چه تعداد گوروتین بازه
Prometheus و Grafana
باید اطلاعات سیستم عامل به این ابزار فرستاده شود تا مصرف کنابع دیده شود
repository layer test
- Isolate Tests
بهتره تست ها جوری باشن که نیازی به ترتیب و پیش نیاز نباشه ، هر تست ، با هر ترتیبی بتونه اجرا بشه
- Use a Test Database
بهتره روی یه دیتابیس دیگه تست انجام بشه
tips
در مانی تست ها همه در دایرکتوری تست قرار دارد ، خوبیش اینه که همه تست ها یه جاست و با خاندن جیسون ، تمام سید ها و داده های تست در دسترسه
ولی مشکل اینجاست که تنها global variable رو میشه تست کرد و نمی توان مقادیر داخلی رو ایمپورت کرد
tdd test driven development
یک رویکرد برای تست نویسی هست و ابتدا تست نوشته میشه ، بعد کد زده میشه
Table-Driven Tests
یه جدول هست شامل ورودی ها ، خروجی ها و درستی یا غلطی خروجی است