نوشتن تست‌های خودکار

در مقاله‌ای در سال ۱۹۷۲ به نام “The Humble Programmer”، Edsger W. Dijkstra گفت:
«آزمایش برنامه می‌تواند راهی بسیار مؤثر برای نشان دادن وجود باگ‌ها باشد، اما برای نشان دادن عدم وجود آن‌ها کاملاً ناکافی است.»
این به این معنی نیست که نباید تلاش کنیم تا جایی که ممکن است آزمایش کنیم!

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

فرض کنید یک تابع به نام add_two می‌نویسیم که ۲ را به هر عددی که به آن پاس داده شود اضافه می‌کند. امضای این تابع یک عدد صحیح به عنوان پارامتر می‌پذیرد و یک عدد صحیح به عنوان نتیجه بازمی‌گرداند. هنگامی که این تابع را پیاده‌سازی و کامپایل می‌کنیم، Rust تمام بررسی‌های نوع و قرض‌گیری را که تا کنون آموخته‌اید انجام می‌دهد تا اطمینان حاصل شود که، به عنوان مثال، ما یک مقدار String یا یک مرجع نامعتبر را به این تابع پاس نمی‌دهیم. اما Rust نمی‌تواند بررسی کند که این تابع دقیقاً همان کاری را که ما قصد داریم انجام دهد، که بازگرداندن پارامتر به علاوه ۲ است نه مثلاً پارامتر به علاوه ۱۰ یا پارامتر منهای ۵۰! اینجا جایی است که تست‌ها وارد می‌شوند.

ما می‌توانیم تست‌هایی بنویسیم که، به عنوان مثال، تأیید می‌کنند که وقتی 3 را به تابع add_two پاس می‌دهیم، مقدار بازگردانده شده 5 است. می‌توانیم این تست‌ها را هر زمان که تغییری در کد خود ایجاد می‌کنیم اجرا کنیم تا مطمئن شویم که هر رفتار درستی که وجود داشته تغییر نکرده است.

تست‌نویسی یک مهارت پیچیده است: اگرچه نمی‌توانیم در یک فصل تمام جزئیات مربوط به نحوه نوشتن تست‌های خوب را پوشش دهیم، در این فصل درباره مکانیک تسهیلات تست Rust بحث خواهیم کرد. درباره حاشیه‌نویسی‌ها و ماکروهایی که هنگام نوشتن تست‌ها در اختیار دارید صحبت خواهیم کرد، رفتار پیش‌فرض و گزینه‌های ارائه‌شده برای اجرای تست‌ها را بررسی خواهیم کرد، و نحوه سازماندهی تست‌ها به تست‌های واحد و تست‌های یکپارچه را یاد خواهیم گرفت.