پنهان کردن تلههای آزمایشی پنهان در Go: اجتناب از مثبتهای کاذب

کابوس در آزمایش مثبت کاذب خواهد بود. «همه چیز در حال گذر است! شگفت انگیز!» تا اینکه در زمان نامعلومی در آینده همه مین ها با هم منفجر می شوند و تیم شما را به جهنم می برند.
دلایل زیادی وجود دارد که آزمایش ها می توانند بی سر و صدا شکست بخورند.
امروز، من قصد دارم در مورد یک دلیل بسیار اساسی صحبت کنم: نمی دانم تست ها کدامند.
اکثر مردم نیمه راه به پروژه Go ملحق می شوند. بیشتر مردم یک زبان را با استفاده از آن در زندگی واقعی یاد می گیرند.
بنابراین، زمانی که شخصی پروژه را با یک چارچوب آزمایشی مانند testify، به احتمال زیاد فکر می کنید روش هایی مانند موارد زیر تست هستند.
func (suite *ExampleTestSuite) TestExample() {
suite.Equal(5, suite.VariableThatShouldStartAtFive)
}
سپس روش دیگری مانند آن را اضافه می کنید TestAnotherCase و پیدا کنید که کار می کند. شما فکر می کنید که کاملاً واضح است که آزمایشات چیست.
آزمایشی که شما در حال صحبت کردن آن هستید ممکن است همان آزمایشی نباشد که بسته Go در حال صحبت کردن است.
از ساخته شده در testing بسته، تست هر تابعی از فرم است
func TestXxx(*testing.T)
البته از آنجایی که ساخته شده است testing بسته دارای ویژگی های محدودی است، اکثر پروژه ها از آن استفاده می کنند testify/suite یا سایر بسته های شخص ثالث مشابه به عنوان چارچوب آزمایشی آنها. تست از testify/suiteنقطه نظر؟
هر روشی که با “تست” شروع می شود را برای افزودن تست ها اضافه کنید
ببینید، ما دو تعریف متفاوت از آزمون داریم.
مشکل هنگام استفاده از ابزار تست شخص ثالث شروع می شود
هنگام استفاده از برخی ابزارها مانند mockery، مطالب زیر را خواهید خواند
شما نگران فراموش کردن آن نخواهید بود
AssertExpectationsفراخوانی روش دیگر… TheAssertExpectationsروش برای فراخوانی در پایان آزمون ها ثبت شده است
عالیه “بنابراین من فقط نیاز به ایجاد یک ماکت دارم و بسته زمانی که رفتارهای مورد انتظار اتفاق می افتد به من اطلاع می دهد.”
آنجا تله است.
چه زمانی mockery می گوید at the end of the tests، در واقع به معنای تعریف از testing ، نه تعریف از testify/suite.
بنابراین وقتی کد زیر را داشته باشید، هر دو را خواهید دید TestA و TestB حتی باید هر دوی آنها از کار بیفتند زیرا راه اندازی ساختگی در آن وجود دارد TestA استفاده می شود در TestB.
package mockandsubtest
import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
)
// Prod code
type ExternalService interface {
Work()
}
type Server struct {
externalService ExternalService
}
func NewServer(externalService ExternalService) *Server {
return &Server{
externalService: externalService,
}
}
// Test code
type ServerSuite struct {
suite.Suite
ExternalService *MockExternalService
Server
}
func TestServerSuite(t *testing.T) {
suite.Run(t, &ServerSuite{})
}
// Run before all test cases
func (s *ServerSuite) SetupSuite() {
s.ExternalService = NewMockExternalService(s.T())
s.Server = Server{externalService: s.ExternalService}
}
// In this test, Work is set up to be called once but not called
func (s *ServerSuite) TestA() {
fmt.Println("TestA is running")
s.ExternalService.EXPECT().Work().Times(1)
}
// In this test, Work is called once unexpectedly
func (s *ServerSuite) TestB() {
fmt.Println("TestB is running")
s.Server.externalService.Work()
}
نتیجه اجرای کد بالا می باشد
TestA is running
TestB is running
PASS
توضیح
فقط معلوم می شود TestServerSuite به عنوان یک آزمون از testing و mockeryدیدگاه به همین دلیل است AssertExpectations در پایان نامیده می شود TestServerSuite ، حتی اگر TestA و TestB به صورت داخلی توسط testify/suite.
از mockeryدیدگاه، s.ExternalService انتظار می رود که یک بار و در واقع یک بار در چرخه حیات فراخوانی شود TestServerSuite. بنابراین انتظار برآورده می شود.
چگونه کاهش دهیم؟
دو راه برای پر کردن شکاف بین آنها وجود دارد testify/suite و testing.
راه اول ایجاد یک ماک جدید قبل از هر روش تست مانند زیر است.
func (s *ServerSuite) SetupTest() {
s.ExternalService = NewMockExternalService(s.T())
}
گاهی اوقات، به دلایل بسیاری مانند راه اندازی یک نمونه سرور برای هر مورد آزمایشی بسیار گران است، در پروژه شما عملی نیست. سپس می توانید جهت دیگر را امتحان کنید، که پس از هر آزمون به صورت دستی ادعا می شود.
مورد دوم در حال افزودن یک تماس از AssertExpectations در پایان هر روش تست مثلا زنگ بزن AssertExpectations در TearDownTest ، که بعد از هر روش تست اجرا می شود.
func (s *ServerSuite) TearDownTest() {
s.ExternalService.AssertExpectations(s.T())
}



