किसी internal Solidity function को टेस्ट करने के लिए, एक child contract बनाएं जो टेस्ट किए जा रहे contract से inherit करता हो, parent contract के internal function को एक external function के साथ रैप (wrap) करें, और फिर child में external function को टेस्ट करें।
Foundry इस inheriting contract को “harness” कहता है, जबकि अन्य इसे “fixture” कहते हैं।
इसे एक्सटेंड (extend) करने में आसान बनाने के लिए function को virtual या public में न बदलें, क्योंकि आप उस contract को टेस्ट करना चाहते हैं जिसे आप वास्तव में डिप्लॉय (deploy) करेंगे।
यहाँ एक उदाहरण दिया गया है।
contract InternalFunction {
function calculateReward(uint256 depositTime) **internal** view returns (uint256 reward) {
reward = (block.timestamp - depositTime) \* REWARD\_RATE\_PER\_SECOND;
}
}
ऊपर दिया गया function हर बीतने वाली समय की इकाई के लिए एक लीनियर (linear) रिवॉर्ड रेट (reward rate) देता है।
fixture (या harness) कुछ इस तरह दिखेगा:
contract InternalFunctionHarness is InternalFunction {
function calculateReward(uint256 depositTime) **external** view returns (uint256 reward) {
reward = super.calculateReward(depositTime);
}
}
जब आप किसी ऐसे parent function को कॉल करते हैं जिसका नाम child के समान है, तो आपको super कीवर्ड (keyword) का उपयोग करना चाहिए, अन्यथा function खुद को कॉल करेगा और इनफिनिट रिकर्सन (infinite recursion) में चला जाएगा।
वैकल्पिक रूप से, आप अपने टेस्ट function को स्पष्ट रूप से harness या fixture के रूप में इस प्रकार लेबल कर सकते हैं:
contract InternalFunctionHarness is InternalFunction {
function calculateReward\_HARNESS(uint256 depositTime) **external** view returns (uint256 reward) {
reward = calculateReward(depositTime);
}
}
function को public में न बदलें
function को public में बदलना कोई अच्छा समाधान नहीं है क्योंकि इससे contract का आकार (size) बढ़ जाएगा। यदि किसी function को public होने की आवश्यकता नहीं है, तो उसे public न बनाएं। यह डिप्लॉयमेंट (deployment) और अन्य functions के निष्पादन (execution) दोनों के लिए गैस कॉस्ट (gas cost) बढ़ा देगा।
जब कोई contract ट्रांज़ैक्शन प्राप्त करता है, तो उसे एक लीनियर (linear) या बाइनरी सर्च (binary search) में सभी public ones (फंक्शन्स) के साथ function selector की तुलना करनी होती है। दोनों ही मामलों में, इसे खोजने के लिए अधिक selectors की आवश्यकता होती है। इसके अलावा, जोड़ा गया selector एक अतिरिक्त बाइटकोड (bytecode) होता है जो डिप्लॉयमेंट कॉस्ट (deployment cost) को बढ़ाता है।
virtual functions को override न करें
मान लीजिए कि हमारे पास निम्नलिखित contract है:
contract InternalFunction {
function calculateReward(uint256 depositTime) **internal** view virtual returns (uint256 reward) {
reward = (block.timestamp - depositTime) \* REWARD\_RATE\_PER\_SECOND;
}
}
सुविधा के लिए इसे fixture पर आसानी से override करना आकर्षक हो सकता है, लेकिन इसकी सलाह नहीं दी जाती है क्योंकि अंततः आप कोड को डुप्लिकेट कर रहे होते हैं और यदि harness में आपका इम्प्लीमेंटेशन (implementation) parent contract से अलग हो जाता है, तो आप वास्तव में अपने बिज़नेस लॉजिक (business logic) का टेस्ट नहीं कर रहे होंगे।
ध्यान दें कि यह विधि हमें मूल कोड को कॉपी और पेस्ट करने के लिए मजबूर करती है:
contract InternalFunctionHarness is InternalFunction {
function calculateReward(uint256 depositTime) **external** view override returns (uint256 reward) {
reward = (block.timestamp - depositTime) \* REWARD\_RATE\_PER\_SECOND;
}
}
private Solidity functions को टेस्ट करने के बारे में क्या?
Solidity में private functions को टेस्ट करने का कोई तरीका नहीं है क्योंकि वे child contract को दिखाई नहीं देते हैं। contract के कंपाइल (compile) होने के बाद internal function और private function के बीच का अंतर मौजूद नहीं रहता है। इसलिए, आप private functions को गैस कॉस्ट (gas cost) पर किसी भी नकारात्मक प्रभाव के बिना internal में बदल सकते हैं।
पाठकों के लिए एक अभ्यास के रूप में, यह देखने के लिए निम्नलिखित कोड को बेंचमार्क (benchmark) करें कि foo को internal में बदलने से गैस कॉस्ट पर कोई प्रभाव नहीं पड़ता है।
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();
}
}
अधिक जानें
अधिक एडवांस टेस्टिंग तरीके (testing methodologies) सीखने के लिए हमारा एडवांस Solidity Bootcamp देखें।
आपकी शुरुआत के लिए हमारे पास एक मुफ़्त Solidity tutorial भी है।
मूल रूप से 6 अप्रैल, 2023 को प्रकाशित