در سالیدیتی، برای انجام تست تابع internal در سالیدیتی نمیتوان مستقیماً آن را فراخوانی کرد، چرا که این نوع توابع فقط از درون همان قرارداد یا قراردادهای مشتقشده قابل دسترسی هستند. به همین دلیل، توسعهدهندگان حرفهای از روشی بهینه به نام harness یا fixture استفاده میکنند که امکان تست این توابع را بدون تغییر در سطح دسترسی یا منطق اصلی قرارداد فراهم میسازد.
در ابزار تست Foundry، به این نوع قرارداد فرزند اصطلاحاً harness گفته میشود، گرچه برخی منابع آن را fixture نیز مینامند.
توجه: هرگز برای راحتی تست، تابع مورد نظر را از internal به public یا virtual تغییر ندهید. زیرا هدف از تست، بررسی همان کدی است که واقعاً قرار است روی بلاک چین مستقر شود، نه نسخهای تغییریافته از آن.
در اینجا یک مثال وجود دارد:
1 2 3 4 5 6 |
contract InternalFunction { function calculateReward(uint256 depositTime) **internal** view returns (uint256 reward) { reward = (block.timestamp - depositTime) \* REWARD\_RATE\_PER\_SECOND; } } |
تابع بالا یک نرخ پاداش خطی را نسبت به زمان سپردهگذاری محاسبه میکند.
حال برای تست این تابع، یک قرارداد فرزند ایجاد میکنیم:
1 2 3 4 5 6 |
contract InternalFunctionHarness is InternalFunction { function calculateReward(uint256 depositTime) **external** view returns (uint256 reward) { reward = super.calculateReward(depositTime); } } |
در اینجا از کلیدواژه super
استفاده شده است تا به نسخه والد تابع دسترسی پیدا کنیم. اگر از super
استفاده نکنیم و مستقیماً calculateReward
را صدا بزنیم، چون نامها یکسان هستند، فراخوانی به خودش باز میگردد و در نهایت منجر به حلقه بینهایت و خطا خواهد شد.
بهجای استفاده از همان نام تابع اصلی، میتوان برای تابع تستی نام متفاوتی انتخاب کرد تا احتمال اشتباه کاهش یابد:
1 2 3 4 5 6 |
contract InternalFunctionHarness is InternalFunction { function calculateReward\_HARNESS(uint256 depositTime) **external** view returns (uint256 reward) { reward = calculateReward(depositTime); } } |
در پروژههای واقعی، استفاده از روش harness برای تست توابع internal در سالیدیتی باعث میشود که هم هزینه تست کاهش یابد و هم ساختار ماژولار قراردادها حفظ شود. این رویکرد نه تنها وابستگی به پیادهسازی را کم میکند، بلکه امکان تست دقیق منطق داخلی را بدون تغییر در سطح دسترسی یا افزایش حجم کد فراهم میسازد؛ روشی که در فرآیند برنامه نویسی قراردادهای سالیدیتی کاربردی و مؤثر است.
چرا نباید تابع internal را public کنیم؟
تغییر سطح دسترسی از internal به public بهظاهر ساده و کاربردی است، اما از نظر فنی توصیه نمیشود:
-
باعث افزایش حجم کد بایتکد (bytecode) میشود.
-
هزینه استقرار (Deployment Gas) را بالا میبرد.
-
به دلیل افزایش تعداد توابع قابل شناسایی، جستجوی selector تابع نیز طولانیتر میشود و این به افزایش هزینه اجرای سایر توابع منجر میشود.
چرا نباید تابع virtual را در fixture بازنویسی کنیم؟
فرض کنید تابع داخلی مورد نظر به شکل زیر تعریف شده باشد:
1 2 3 4 5 6 |
contract InternalFunction { function calculateReward(uint256 depositTime) **internal** view virtual returns (uint256 reward) { reward = (block.timestamp - depositTime) \* REWARD\_RATE\_PER\_SECOND; } } |
1 2 3 4 5 6 |
contract InternalFunctionHarness in InternalFunction { function calculateReward(uint256 depositTime) **external** view override returns (uint256 reward) { reward = (block.timestamp - depositTime) \* REWARD\_RATE\_PER\_SECOND; } } |
آیا میتوان توابع private را تست کرد؟
خیر. توابع private
حتی در قراردادهای مشتق شده نیز قابل مشاهده نیستند، بنابراین بههیچوجه نمیتوان آنها را مستقیماً تست کرد.
اما نکته مهمتر اینکه پس از کامپایل شدن قرارداد، تفاوتی میان internal و private وجود ندارد. بنابراین اگر نیاز به تست تابعی دارید که در حال حاضر private است، میتوانید با خیال راحت آن را به internal تغییر دهید. این کار هیچ تأثیری روی مصرف گس یا عملکرد قرارداد نخواهد داشت.
در مثال زیر، اگر تابع foo
را از private به internal تغییر دهید، مصرف گس همچنان ثابت میماند:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
contract A { // change this to be private function foo() **internal** pure returns (uint256 f) { f = 2; } function bar() **internal** pure returns (uint256 b) { b = foo(); } } contract B is A { // 146 gas: 0.8.7 no optimizer function baz() **external** pure returns (uint256 b) { b = bar(); } } |
راستی! برای دریافت مطالب جدید در کانال تلگرام یا پیج اینستاگرام سورس باران عضو شوید.
- انتشار: ۵ خرداد ۱۴۰۴
دسته بندی موضوعات
- آموزش ارز دیجیتال
- آموزش برنامه نویسی
- آموزش متنی برنامه نویسی
- اطلاعیه و سایر مطالب
- پروژه برنامه نویسی
- دوره های تخصصی برنامه نویسی
- رپورتاژ
- فیلم های آموزشی
- ++C
- ADO.NET
- Adobe Flash
- Ajax
- AngularJS
- apache
- ARM
- Asp.Net
- ASP.NET MVC
- AVR
- Bootstrap
- CCNA
- CCNP
- CMD
- CSS
- Dreameaver
- EntityFramework
- HTML
- IOS
- jquery
- Linq
- Mysql
- Oracle
- PHP
- PHPMyAdmin
- Rational Rose
- silver light
- SQL Server
- Stimulsoft Reports
- Telerik
- UML
- VB.NET&VB6
- WPF
- Xml
- آموزش های پروژه محور
- اتوکد
- الگوریتم تقریبی
- امنیت
- اندروید
- اندروید استودیو
- بک ترک
- بیسیک فور اندروید
- پایتون
- جاوا
- جاوا اسکریپت
- جوملا
- دلفی
- دوره آموزش Go
- دوره های رایگان پیشنهادی
- زامارین
- سئو
- ساخت CMS
- سی شارپ
- شبکه و مجازی سازی
- طراحی الگوریتم
- طراحی بازی
- طراحی وب
- فتوشاپ
- فریم ورک codeigniter
- فلاتر
- کانستراکت
- کریستال ریپورت
- لاراول
- معماری کامپیوتر
- مهندسی اینترنت
- هوش مصنوعی
- یونیتی
- کتاب های آموزشی
- Android
- ASP.NET
- AVR
- LINQ
- php
- Workflow
- اچ تی ام ال
- بانک اطلاعاتی
- برنامه نویسی سوکت
- برنامه نویسی موبایل
- پاسکال
- پایان نامه
- پایتون
- جاوا
- جاوا اسکریپت
- جی کوئری
- داده کاوی
- دلفی
- رباتیک
- سئو
- سایر کتاب ها
- سخت افزار
- سی اس اس
- سی پلاس پلاس
- سی شارپ
- طراحی الگوریتم
- فتوشاپ
- مقاله
- مهندسی نرم افزار
- هک و امنیت
- هوش مصنوعی
- ویژوال بیسیک
- نرم افزار و ابزار برنامه نویسی
- وردپرس