سلام، دنیا
سلام دنیا
شما میتوانید کدهای این بخش را اینجا ببینید
یک رسم قدیمی است که اولین مسئلهی برنامهنویسی در یک زبان Hello, World یا سلام دنیا باشد.
هر جا که میخواهید یک فولدر بسازید
فایل
hello.go
را ایجاد کنید و محتوای زیر را در آن بنویسید
برای اجرای آن دستور go run hello.go
را بزنید.
نحوهی کار
زمانی که شما یک کد گو مینویسید، شما یک بستهی main
دارید که در آن تابع main
تعریف شده است. شما میتوانید کدهای مرتبط به هر بخش را در بستهی خاص خود بگذارید.
برای تعریف تابع شما از کلمهی کلیدی func
باید استفاده کنید و بعد از آن نام تابع را بنویسید.
با دستور import "fmt"
ما میتوانیم از یک بسته که دارای تابعPrintln
هست استفاده کنیم.
چگونه تست کنیم
چگونه جنین چیزی را میتوان تست کرد؟ خوب است که کدهای «دامنه» را از دنیای بیرون جدا کرد. fmt.Println
مربوط به دامنهی شما نیست. اما رشتهای که میفرستیم جزو دامنهی کد ما هست.
پس میتوان این دو را از هم جدا کرد.
ما دوباره یک تابع جدید ساختیم اما این بار پس از تعریف تابع از کلمهی کلیدی string
استفاده کردیم که یعنی وظیفهی تابع بازگرداندن یک رشته است.
حال یک فایل جدید با نام hello_test.go
میسازیم که در آن تستهای مربوط به تابغ Hello
را مینویسیم.
ماژولهای گو؟
گام بعدی اجرای تست است. دستور go test
را در ترمینال بزنید. اگر تستها پاس شد احتمالا دارید از نسخههای قدیمیتر گو استفاده میکنید. اگر از نسخهی ۱.۱۶ یا جدیدتر استفاده میکنید پس احتمالا کد شما اصلا اجرا نمیشود، و شما چنین خطابب در ترمینال میبینید:
مشکل چیست? اگر بخواهیم در یک کلمه مشکل را بگوییم، مشکل, ماژولها هستند. خوشبحتانه راه حل آن ساده است. دستور go mod init hello
را در ترمینال وارد کنید. این دستور فایلی با محتوای زیر برای شما تولید میکند:
این فایل به go
اطلاعات اساسی مربوط به کد شما را میدهد. اگر تصمیم دارید برنامهی خود را به دیگران بدهید، شما هم باید بگویید که کد را از کجا بگیرد، هم اینکه این کد چه نیازمندیهایی برای اجرا دارد. در حال حاضر ماژول شما حداقلها را دارد، و فعلا میتواند اینگونه باشد. برای آنکه اطلاعات بیشتری دربارهی ماژول داشته باشید میتوانید به مستندات گو در مورد ماژول مراجعه کنید. حالا که تست میتواند اجرا شود به سراغ ادامهی کار میرویم.
در بخشهای بعدی بخاطر داشته باشید فبل از دستورات go test
و go build
باید ابتدا دستور go mod init SOMENAME
را بزنید تا ماژول ساخته شود.
بازگشت به تست
حالا اگر go test
را بزنید تست شما باید موفق باشد، برای اینکه مطمئنتر باشید، میتوانید رشتهی موجود در want
را تغییر دهید؛ تست باید خطا بدهد.
اگر متوجه شده باشید ما نیازی به نصب فریمورک برای تست کدمان نداریم، در گو خود زبان امکان تست را برای شما فراهم کرده و با همون دستور زبان گو میتوان تست نوشت.
نوشتن تست
نوشتن تست مانند نوشتن تابع هست، فقط باید چند شرط را رعایت کرد.
نام فایلی که تست در آن نوشته میشود باید به شکل
xxx_test.go
باشدنام تابع تست باید با
Test
شروع شودتابع تست تنها یک آرگومان میگیرد و آن
t *testing.T
استبرای استفاده از
*testing.T
شما نیاز دارید با زدنimport testing
, کتابخانهی مربوط به تست را در کد خود ایمپورت کنید.
فعلا کافیست بدانید که t
که از نوع *testing.T
بود درواقع یک رابط برای صحبت با فریمورک تست هست و میتوان دستوراتی همچون ()t.Fail
را وارد کرد.
ما یک سری دستورات جدید را دیدیم:
دستور if
دستور if
در زبان گو مانند همین دستور در دیگر زبانها میشد
تعریف متغیر
ما با دستور varName := value
یک متغیر جدید تعریف میکنیم که به ما اجازه میدهد از یک سری مغادیر چندن بار استفاده کنیم تا خوانایی کد بالا برود.
دستور t.Errorf
ما متد Errorf
را که برای t
تعریف شده صدا میزنیم تا به وسیلهی آن اعلام کنیم که تست ما موفق نبوده. حرف f
از کلمهی فرمت گرفته شده که به ما اجازه میدهد یک رشته داشته باشیم که به جای %q
مقدار متغیر را در آن بگذاریم، این باعث میشود متن خطای ما خوانا باشد، تا در صورت داشتن خطا مشکل را سریعتر بفهمیم.
شما میتوانید در مورد این مدل کار با رشته در مستندات گو بیشتر بخوانید. برای تست استفاده از %q
بسیار مناسب است چرا که مقدار متغبر را داخل دابل کوتیشن میگذارد.
ما جلوتر به تفاوت تابع و متد میپردازیم.
مستندات گو
یکی دیگر از ویژگیهای ممتاز گو مستندات آن هست شما میتوانید با زدن دستور godoc -http :8000
مستندات گو را در سیستم خود داشته باشید. اگر به آدرس localhost:8000/pkg بروید شما تمام بستههای نصب شده روی سیستم خود را میبینید.
بیشتر کتابخانههای استاندارد گو مستندات عالیای دارند که همراه مثال هست. بد نیست به آدرس http://localhost:8000/pkg/testing/ بروید و در مستندات مربوط به کتابخانهی تست چرخی بزنید.
اگر در سیستمتان دستور godoc
را ندارید احتمالا بخاطر آن است که از نسخههای جدیدتر گو استفاده میکنید. شما میتوانید با زدن دستور go install golang.org/x/tools/cmd/godoc@latest
برنامهی نشان دادن مستندات را نصب کنید.
سلام بر تو
جالا که تست ما کار میکند میتوانیم خیالمان از بابت امنیت کدمان راحت باشد.
در آخرین مثالمان ما تست را بعد از نوشتن کد اصلی نوشتیم، تا نگاهی داشته باشیم به چگونگی کارکرد تست. از اینجا به بعد ما تست را قبل از نوشتن کد تابع اصلی مینویسیم.
در گام بعدی میبینیم که چگونه نام شخص را موقع سلام کردن مشخص کنیم.
بیایید ابتدا نیازمندی خود را در تست مشخص کنیم. این یک برنامهنویس تست محور مقدماتی هست و به ما اجازه میدهد تا مطمئن شویم تست ما واقعا چیزی که ما میخواهیم را تست میکند. گاهی اوقات هنگام کد نوشتن تست شما حتا اگر با خطا هم مواجه باشد موفق است، در این مواقع شما به درستی تست نمیکنید. باید مطمئن شوید که تستتان در صورت وجود مشکل خطا بدهد.
حال دستور go test
را بزنید شما باید خطای زمان کامپایل بگیرید
```text ./hello_test.go:6:18: too many arguments in call to Hello have (string) want () ```
وقتی با یک زبان برنامهنویسی ایستا (Statically typed programming languages) مانند گو سروکار دارید، بهتر است به حرف کامپایلر گوش کنید، در این زیانها کامپایلر میداند کد چگونه کار میکند تا شما مجبور نباشید آن را بدانید.
در اینجا کامپایلر به شما میگوید نیاز دارید چه تغییری بدهید تا کد درست کار کند، ما باید تابع Hello
را تغییر دهیم تا یک آرگومان بگیرد.
تابع Hello
را به شکل زیر تغییر دهید تا یک آرگومان بگیرد.
```go func Hello(name string) string { return "Hello, world" } ```
اگر دوباره تست خود را اجرا کنید خطا میگیرید چرا که هنگام صدا زدن تابع Hello
باید یک آرگومان هم وارد کنید.
```go func main() { fmt.Println(Hello("world")) } ```
حالا موقع اجرای تست چنین پیامی باید ببینید
```text hello_test.go:10: got 'Hello, world' want 'Hello, Chris'' ```
بالاخره کد ما قابل تست شد اما باز هم تست موفقیتآمیز نبود.
حال وقت آن است که با تغییر تابع Hello
کاری کنیم که نتیجهی مقبول ما را بدهد.
```go func Hello(name string) string { return "Hello, " + name } ```
حالا وقتی تست را اجرا کنیم تست با موفقیت پاس میشود. براساس چرخهی برنامهنویسی تست محور حالا وقت ریفکتور میباشد.
بادداشتی برای استفاده از سورس کنترل
در این نقطه اگر از یک سورس کنترل استفاده میکنید(که باید بکنید) بهتر است کد خود را commit
کنید چرا که در این نقطه ما یک نرمافزار قابل اجرا داریم که تست هم برای آن نوشته شده.
البته من بنا ندارم کد را به مخزن بفرستم چراکه میخواهم آن را ریفکتور کنم. ولی بهتر است تغییرات را کامیت کنید که اگر هنگام ریفکتور به مشکل خوردید به راحتی به ورژن موفق قبلی برگردید.
چیز خیلی زیادی برای زیفکتور کردن نیست اما بد نیست اینجا با مفهوم ثابتها آشنا شوید.
ثابتها
ثابتها مانند زیر تعریف میشوند.
حالا ما میتوانیم کد خود را ریفکتور کنیم
بعد از ریفکتور کردن یک بار دیگر تستها را اجرا کنید تا مطمئن شوید چیزی خراب نشده باشد.
خوب است کمی دربارهی ساختن ثابت فکر کنید تا کاربرد آن در برنامه و حتا پرفورمنس را بهتر درک کنید.
سلام دنیا...دوباره
خوب است در گام بعدی کاری کنیم که اگر یک رشتهی خالی به کد دادیم به ما «Hello, World» تحویل دهد نه «Hello, »
کارمان را با نوشتن تست جدید شروع میکنیم
حالا ما یک مفهوم دیگر را معرفی میکنیم، زیر مجموعهها. گاهی حوب است که تستهایمان را حول یک چیز گروهبندی کنیم و بعد یک زیرمجموعه داشته باشیم که سناریوهای متقاوت از آن چیز را تست کند.
خوبی این روش این است که شما میتوانید یک بخش از کد را به اشتراک بگذارید تا در دیگر تستها از آن استفاده شود.
حالا بیایید با استفاده از if
کاری کنیم تستمان درست کار کند.
حالا اگر تستهای خود را اجرا کنیم باید ببینیم که تستها موفق هستند، و چیزی خراب نشده.
مهم هست که تستهای شما به شکل شفاف هر آنچه مورد نیاز هست را تست کرده باشد. اما این موضوع باعث تکرار کردن در کد میشود.
ریفکتور تنها برای کد اصلی نیست!
جالا که تستها موفق هستند، خوب است که خود تستها را ریفکتور کنیم
ما اینجا چه کار کردیم؟
ما بخشی از کد را که چند بار تکرار میشد، در یک تابع مجزا گذاشتیم، از این پس هر وقت خواستیم برابری دو رشته برای تست را بسنجیم، این تابع را صدا میزنیم.
برای این دست توابع کمکی، خوب است که از testing.TB
به عنوان آرگومان استفاده کنیم، این یک اینترفیس است که جای هر دوی *testing.T
و *testing.B
کار میکند و ما هم برای تست و هم برای بنچمارک میتوانیم از آن استفاده کنیم.(نگران نباشید اگر معنی کلماتی مانند اینترفیس را نمیدانید. در آینده به آنها میپردازیم).
تابع t.Helper()
برای این نیاز است که بگوییم این یک تابع کمکی است. تا در صورت وجود خطا شمارهی خط خطا را به گونهای میدهد انگار که داخل تابع تست به مشکل خورده است. اگر متوجه نمیشوید کاری کنید تست خطا بدهد، و خط t.Helper()
را کامنت کنید تا ببینید متن خطا به چه شکل است. کامنت راهی فوقالعاده برای اضافه کردن اطلاعات بیشتر به کد هست، یا در این مورد خاص حذف کردن یک خط از کد بدون اینکه واقعا کد را حذف کنید. برای این کار دو اسلش به ابتدای خط اضافه کنید، احتمالا رنگ کد در ادیتورتان تغییر کند.
بازگشت به سورس کنترل
حالا ما از نتیجهی تغییراتمان راضی هستیم پس بهتر است همینجا دوباره کد را کامیت کنیم.
نظم
بیاییم یک دور چرحه را مرور کنیم
نوشتن تست
حذف خطاهای کامپایلر
اجرای تست و اطمینان از گرفتن خطا، چک کردن معنادار بودن متن خطا
نوشتن کد کافی برای پاس شدن تست
ریفکتور
شاید به نظر این کارها مسخره باشد، اما تعهد به چرخه بسیار مهم است.
نه تنها باعث میشود مطمئن شوید تستهای مناسبی نوشتهاید، بلکه کمک میکند یک ساختار خوب داشته باشید و با امنیت ریفکتور کنید.
اینکه بگذارید تست خطا بدهد مهم است، چرا که میبینید متن خطای شما به چه شکلی است. اگر نتوانید خطا را به درستی یفهمید کار شما به عنوان برنامهنویس بسیار سخت میشود.
وقتی از سرعت تستهایتان مطمئن شدید، و ابزارهای مورد نیاز برای اجرای راحتتر تستها را آماده کردید. شما به راحتی میتوانید این چرحه را تکرار کنید.
با ننوشتن تست شما باید به شکل دستی از درستی کدتان مطمئن شوید و این در بلند مدت به شدت از شما زمان میبرد
##ادامه بدهید! نیازمندیهای بیشتر
حالا نیازمندیهای ما بیشتر شده ما نیاز داریم یک آرگومان دیگر را هم دریافت کنیم، ما باید زبانی که با آن به شخص سلام میدهیم را هم مشخص کنیم، و اگر زبانی که داده شده را در لیست زبانهایمان نداریم به همان انگلیسی سلام کنیم.
ما باید خیالمان راحت باشد که با برنامهنویسی تست محور به راحتی و با اطمینان میتوان این خاصیت را اضافه کرد.
یک تست برای زبان اسپانیایی اضافه میکنیم.
```go t.Run("in Spanish", func(t *testing.T) { got := Hello("Elodie", "Spanish") want := "Hola, Elodie" assertCorrectMessage(t, got, want) }) ```
یادتان باشد چرخه را دور نزنید، اول تست مینویسیم. وقتی سعی میکنید تست را اجرا کنیپ کامپایلر خطا میدهد چرا که سعی دارید با دو آرگومان Hello
را صدا بزنید.
```text ./hello_test.go:27:19: too many arguments in call to Hello have (string, string) want (string) ```
با اضافه کردن یک آرگومان دیگر به Hello
این مشکل را برطرف کنید
```go func Hello(name string, language string) string { if name == "" { name = "World" } return englishHelloPrefix + name } ```
وقتی سعی کنید تستها را اجرا کنید این بار خطا میدهد که دیگر تستهای موجود به اندازهی کافی آرگومان ندارند.
با اضافه کردن یک رشتهی خالی به آرگومانهای تستهای دیگر مشکل آنها را برطرف کنید، حالا همهی تستها باید پاس شوند به جز آخرین تست.
```text hello_test.go:29: got 'Hello, Elodie' want 'Hola, Elodie' ```
ما از یک if
استفاده میکنیم که اگر زبان اسپانیایی بود کلمهی سلام را به زبان اسپانیایی بنویسد
حالا تستها باید پاس شوند.
حالا زمان ریفکتور است. شما باید متوجه بعضی مشکلات بشوید، رشتههای جادویی که بعضی از آنها چندین بار تکرار شده. سعی کنید خودتان کد را ریفکتور کنید و مطمئن بشید هر بار پس از ریفکتور تستها را اجرا کنید تا چیزی خراب نشده باشد.
فرانسوی
یک تست بنویسید که اگر زبان
"French"
وارد شد برای سلام"Bonjour, "
بگیریدببینید خطا میخورد، و مطمئن شوید متن خطا خوانا است
کمترین تغییر قابل قبول را در کد بدهید تا تستها پاس شود
احتمالا چیزی که مینویسید مانند زیر باشد
دستور switch
دستور switch
وقتی کلی دستور if
دارید معمولا بهتر است به جای آن از دستور switch
استفاده کنید. ما میتوانید کد را به شکلی ریفکتور کنیم که از این دستور استفاده شود تا خوانایی کد بیشتر شود و در آینده به راحتی از زبانهای بیشتری بشود پشتیبانی کرد.
حالا یک زبان به انتخاب خودتان اضافه کنید تا ببینید اضافه شدن زبان جدید چقدر راحتتر شده است.
یک...ریفکتور...دیگر؟
ممکن است بگویید که تابع ما کمی بزرگ شده است. سادهترین ریفکتور این است که بخشی از کار را به تابع دیگری منتقل کنیم
چند مفهوم جدید:
در امضای تابع ما برای مقدار بازگشتی اسم مشخص کردیم
(prefix string)
.این کار یک متغیر به اسم
prefix
در تابع شما ایجاد میکندمقدار این متغیر صفر میباشد، اینکه صفر چه باشد براساس نوع متغیر مشخص میشود مثلا
int
عدد صفر است وstring
رشتهی خالیشما تنها با نوشتن عبارت
return
مقدار مورد نظر را برمیگردانید و نیازی به نوشتنreturn prefix
نمیباشد.
در مستندات تابع شما این موضوع نشان داده میشود تا کد شما خواناتر باشد.
عبارت
default
وقتی اجرا میشود که هیچکدام از گزینههای موجود درswitch
اجرایی نشده باشند.نام این تابع با حروف کوچک شروع شده، در گو اگر بخواهیم تابع را از خارج از بستهی کد صدا بزنیم(به اصطلاع تابع عمومی باشد) نام آن را با حروف بزرگ شروع میکنیم و در صورتی که بخواهیم تنها از داخل بسته صدا زده شود نام آن را با حروف کوچک شروع میکنیم(تابع خصوصی است). ما نمیخواهیم توابع داخلی بسته برای جای دیگر نشان داده شود پس نام آن را با حروف کوچک شروع میکنیم.
همچنین ما میتوانید ثابتها را در یک گروه با یک دیگر تعریف کنیم، این کار خوبی هست که ثابتهای مرتبط با هم یکجا تعریف شوند، تا خوانایی کد بالا برود.
جمعبندی
چه کسی فکر میکرد که بتوان برای تابع Hello, world
این همه کار کرد؟
تا به اینجا شما باید اطلاعات زیر را بدانید:
بخشی از سینتکس گو
نوشتن تست
تعریف تابع با آرگومانها و مقدار بازگشتی
دستورات
if
،const
وswitch
تعریف متغیر و ثابت
فرایند برنامهنویسی تست محور و اهمیت تکرار فرایند
نوشتن یک تست که به خطا میخورد و دیدن به خطا خوردن آن، تا از یک طرف مطمئن شویم تستی که نوشتیم به تابع ما مرتبط هست و با مشکل داشتن تابع خطا میدهد، و از طرفی متن خطا را ببینیم تا مطمئن شویم که متن خطا خوانا است.
نوشتن کمترین کد مورد نیاز برای پاس شدن تست تا بدانیم که کد ما کار میکند.
ریفکتور کد با در نظر گرفتن تستها تا از بابت راحتی تغییر مطمئن شویم و بدانیم ساختار کدمان درست تعریف شده.
در موردی که بررسی کردیم ما از تابع Hello()
شروع کردیم، و سپس به تابعهای Hello("name")
و Hello("name", "french")
رسیدیم و این کار را در گامهای کوچک و قابل فهم انجام دادیم.
البته این کارها نسبت به مسائل اصلی دنیای واقعی بسیار ساده هست، اما اصول آن یکی است. برنامهنویسی تست محور مهارتی هست که یادگیری آن نیاز به تمرین دارد، اما به شکستن مسئله به مسائل کوچکتر کار شما برای نوشتن نرمافزار خیلی راحتتر میشود.
Last updated