Let's Go تست › سفارشی‌سازی نحوه اجرای تست‌ها
قبلی · فهرست · بعدی
فصل ۱۳.۴.

سفارشی‌سازی نحوه اجرای تست‌ها (Customizing How Tests Run)

در این بخش، نحوه سفارشی‌سازی اجرای تست‌ها (Customizing Test Execution) را بررسی می‌کنیم. این شامل پرچم‌های تست (Test Flags) و متغیرهای محیطی (Environment Variables) می‌شود.

همچنین با تنظیمات تست (Test Settings) و پیکربندی تست (Test Configuration) آشنا خواهیم شد.

کنترل اینکه کدام تست‌ها اجرا شوند

تا کنون در این کتاب، ما تست‌ها را در یک پکیج خاص (پکیج cmd/web) به این صورت اجرا کرده‌ایم:

$ go test ./cmd/web

اما همچنین می‌توان تمام تست‌ها را در پروژه فعلی خود با استفاده از الگوی وایلدکارد ./... اجرا کرد. در مورد ما، می‌توانیم از آن برای اجرای تمام تست‌ها در پروژه خود به این صورت استفاده کنیم:

$ go test ./...
ok      snippetbox.alexedwards.net/cmd/web      0.007s
?       snippetbox.alexedwards.net/internal/models      [no test files]
?       snippetbox.alexedwards.net/internal/validator   [no test files]
?       snippetbox.alexedwards.net/ui   [no test files]

یا در جهت دیگر، می‌توان فقط تست‌های خاصی را با استفاده از فلگ -run اجرا کرد. این به شما اجازه می‌دهد یک عبارت منظم مشخص کنید و فقط تست‌هایی که نامشان با عبارت منظم مطابقت دارد اجرا شوند.

برای مثال، می‌توانیم انتخاب کنیم که فقط تست TestPing را به این صورت اجرا کنیم:

$ go test -v -run="^TestPing$" ./cmd/web/
=== RUN   TestPing
--- PASS: TestPing (0.00s)
PASS
ok      snippetbox.alexedwards.net/cmd/web      0.008s

و حتی می‌توانید از فلگ -run برای محدود کردن تست به برخی زیرتست‌های خاص با استفاده از فرمت {test regexp}/{sub-test regexp} استفاده کنید. برای مثال برای اجرای زیرتست UTC از تست TestHumanDate می‌توانیم این کار را انجام دهیم:

$ go test -v -run="^TestHumanDate$/^UTC$" ./cmd/web
=== RUN   TestHumanDate
=== RUN   TestHumanDate/UTC
--- PASS: TestHumanDate (0.00s)
    --- PASS: TestHumanDate/UTC (0.00s)
PASS
ok      snippetbox.alexedwards.net/cmd/web    0.003s

در مقابل، می‌توانید از اجرای تست‌های خاصی با استفاده از فلگ -skip جلوگیری کنید. مانند فلگ -run که به تازگی بررسی کردیم، این به شما اجازه می‌دهد یک عبارت منظم مشخص کنید و هر تستی که نامش با عبارت منظم مطابقت دارد اجرا نخواهد شد. برای مثال، برای رد کردن تست TestHumanDate:

$ go test -v -skip="^TestHumanDate$" ./cmd/web/
=== RUN   TestPing
--- PASS: TestPing (0.00s)
=== RUN   TestCommonHeaders
--- PASS: TestCommonHeaders (0.00s)
PASS
ok      snippetbox.alexedwards.net/cmd/web      0.006s

کشینگ تست

شاید تا کنون متوجه شده‌اید که اگر دقیقاً همان تست را دو بار اجرا کنید — بدون ایجاد هیچ تغییری در پکیجی که در حال تست آن هستید — سپس یک نسخه کش‌شده از نتیجه تست نمایش داده می‌شود (که با علامت (cached) در کنار نام پکیج نشان داده می‌شود).

$ go test ./cmd/web
ok      snippetbox.alexedwards.net/cmd/web      (cached)

در بیشتر موارد، کشینگ نتایج تست واقعاً مفید است (به خصوص برای کدبیس‌های بزرگ) زیرا به کاهش زمان کلی اجرای تست کمک می‌کند. اما اگر می‌خواهید تست‌های خود را به طور کامل اجرا کنید (و از کش اجتناب کنید) می‌توانید از فلگ -count=1 استفاده کنید:

$ go test -count=1 ./cmd/web 

به طور متناوب، می‌توانید نتایج کش‌شده برای تمام تست‌ها را با استفاده از دستور go clean پاک کنید:

$ go clean -testcache   

شکست سریع

همانطور که چند فصل پیش به طور مختصر اشاره کردم، وقتی از تابع t.Errorf() برای علامت‌گذاری یک تست به عنوان شکست‌خورده استفاده می‌کنید، باعث نمی‌شود که go test بلافاصله خارج شود. تمام تست‌های دیگر شما (و زیرتست‌ها) پس از یک شکست ادامه خواهند یافت.

اگر ترجیح می‌دهید تست‌ها بلافاصله پس از اولین شکست متوقف شوند، می‌توانید از فلگ -failfast استفاده کنید:

$ go test -failfast ./cmd/web

مهم است که توجه داشته باشید که فلگ -failfast فقط تست‌ها را در پکیجی که شکست داشته است متوقف می‌کند. اگر در حال اجرای تست‌ها در چندین پکیج هستید (برای مثال با استفاده از go test ./...)، سپس تست‌ها در پکیج‌های دیگر ادامه خواهند یافت.

تست موازی

به طور پیش‌فرض، دستور go test تمام تست‌ها را به صورت سریالی اجرا می‌کند، یکی پس از دیگری. وقتی تعداد کمی تست دارید (مانند ما) و زمان اجرا بسیار سریع است، این کاملاً مناسب است.

اما اگر صدها یا هزاران تست داشته باشید، زمان اجرای کل می‌تواند به چیزی معنادار تبدیل شود. و در آن سناریو، ممکن است با اجرای تست‌ها به صورت موازی، مقداری زمان صرفه‌جویی کنید.

می‌توانید نشان دهید که اجرای یک تست به صورت همزمان با دیگر تست‌ها مشکلی ندارد با فراخوانی تابع t.Parallel() در ابتدای تست. برای مثال:

func TestPing(t *testing.T) {
    t.Parallel()

    ...
}

مهم است که در اینجا توجه داشته باشید که:

فعال‌سازی آشکارساز رقابت

دستور go test شامل یک فلگ -race است که آشکارساز رقابت Go را هنگام اجرای تست‌ها فعال می‌کند.

اگر کدی که در حال تست آن هستید از همزمانی استفاده می‌کند، یا در حال اجرای تست‌ها به صورت موازی هستید، فعال‌سازی این می‌تواند ایده خوبی باشد تا شرایط رقابتی که در برنامه شما وجود دارد را پرچم‌گذاری کند. می‌توانید از آن به این صورت استفاده کنید:

$ go test -race ./cmd/web/

باید بدانید که آشکارساز رقابت در مفید بودن خود محدود است... این فقط یک ابزار است که شرایط رقابتی را اگر و زمانی که در زمان اجرا در طول تست شناسایی شوند، پرچم‌گذاری می‌کند. این تحلیل استاتیک از کدبیس شما انجام نمی‌دهد، و یک اجرای بدون مشکل تضمین نمی‌کند که کد شما از شرایط رقابتی خالی است.

فعال‌سازی آشکارساز رقابت همچنین زمان کلی اجرای تست‌های شما را افزایش خواهد داد. بنابراین اگر در حال اجرای تست‌ها به صورت بسیار مکرر به عنوان بخشی از یک جریان کاری TDD هستید، ممکن است ترجیح دهید از فلگ -race فقط در طول اجرای تست‌های پیش از تعهد استفاده کنید.

واژه‌نامه اصطلاحات فنی

اصطلاح فارسی معادل انگلیسی توضیح
سفارشی‌سازی اجرای تست‌ها Customizing Test Execution تنظیم نحوه اجرای تست‌ها
پرچم‌های تست Test Flags گزینه‌های خط فرمان تست
متغیرهای محیطی Environment Variables متغیرهای سیستمی
تنظیمات تست Test Settings پیکربندی اجرای تست
پیکربندی تست Test Configuration تنظیمات محیط تست
زمان اجرا Runtime زمان اجرای برنامه
پارامترهای تست Test Parameters مقادیر ورودی تست
گزینه‌های اجرا Execution Options تنظیمات اجرا
مسیر اجرا Execution Path مسیر پردازش تست
خروجی تست Test Output نتایج اجرای تست