كيفية اختبار العقود الذكية

الصورة

لا يمكن تغيير شروط العقد الذكي. لذلك ، كلما قمت بإنشاء عقد ذكي ، فأنت بحاجة إلى التأكد من أنه يعمل بشكل صحيح. الاختبار طريقة آمنة لاختبار العقد في مواقف مختلفة. في هذا البرنامج التعليمي ، ستتعلم الخطوات التي يجب اتخاذها.

سأقول:

  1. كيفية تحضير بيئة اختبار.
  2. كيفية كتابة اختبارات JavaScript وتنفيذها في Truffle .

تم تصميم البرنامج التعليمي للمبتدئين الذين بدأوا للتو في الخوض في تطوير واختبار العقود الذكية على Ethereum. لفهم هذا البرنامج التعليمي ، يجب أن يكون لديك على الأقل معرفة أساسية بـ JavaScript و Solidity .

1. كيفية إعداد بيئة اختبار


هناك العديد من الطرق لاختبار العقود الذكية ، لكن Truffle هو أكثر أدوات كتابة الاختبارات شيوعًا باستخدام JavaScript . على Truffle ، يمكنك كتابة اختبارات الوحدة ، وكذلك إجراء اختبار تكامل كامل مع معلمات حقيقية من بيئة الإنتاج.

تحتاج أولاً إلى تثبيت أحدث إصدار من Node.js من الموقع الرسمي .
ثم افتح المحطة الطرفية وقم بتثبيت Truffle باستخدام الأمر التالي:

npm install -g truffle 

بعد تثبيت Truffle ، دون إغلاق الجهاز ، أنشئ دليل التمويل :

 mkdir Funding 

بعد ذلك ، انتقل إلى الدليل باستخدام الأمر:

 cd Funding 

لتهيئة الدليل ، قم بتشغيل الأمر:

 truffle init 

بعد تنفيذ الأمر ، سيتم إنشاء المجلدات والملفات التالية في دليل التمويل :

الصورة

كذلك سوف نعمل مع كل دليل. في غضون ذلك ، نواصل إعداد بيئة الاختبار.

لتشغيل الاختبارات ، تحتاج إلى مكتبات Javascript.

Mocha هي مكتبة تحتوي على وظائف شائعة للاختبار ، بما في ذلك وصفها .

تشاي هي مكتبة تدعم مجموعة متنوعة من الوظائف للشيكات. هناك "أنماط" مختلفة للتحقق من النتائج ، ويوفر لنا Chai هذه الفرصة. في البرنامج التعليمي سوف نستخدم ينبغي .

بشكل افتراضي ، Mocha جزء من Truffle ، يمكننا بسهولة استخدام وظائف المكتبة. يجب أن يتم تثبيت تشاي يدويا. للقيام بذلك ، استخدم الطرفي وفي الدليل الجذر للمشروع ، قم بتشغيل الأمر:

 npm install chai 

لقد قمت أيضًا بتثبيت مكتبة chai-bignumber لمقارنة الأرقام بدقة تعسفية:

 npm install --save-dev chai-bignumber 

بيئة الاختبار جاهزة لهذا. يمكنك الآن البدء في تطوير عقد ذكي واختباراته.

2. كيفية كتابة اختبارات JavaScript وتنفيذها في Truffle


لتطوير الاختبارات ، تحتاج إلى عقد ذكي. سنقوم بتطوير عقد يسمح لك بجمع التبرعات ، وتحديد مبلغ معين لتحقيق التحصيل وسحب الأموال. إذا تبرع شخص ما أكثر ، فسيعاد إليه الفرق بين المبلغ المتراكم والمبلغ الذي يجب تحصيله.

انتقل إلى التمويل -> دليل العقود . في التمويل / العقود ، قم بإنشاء ملف Funding.sol بالملحق .sol - سيكون هذا هو العقد الذكي للاختبار.

في Funding.sol ، أضف الكود التالي:

 pragma solidity 0.4.24; contract Funding { uint public raised; uint public goal; address public owner; event Donated(uint donation); event Withdrew(uint amount); modifier onlyOwner() { require(owner == msg.sender); _; } modifier isFinished() { require(isFunded()); _; } modifier notFinished() { require(!isFunded()); _; } constructor (uint _goal) public { owner = msg.sender; goal = _goal; } function isFunded() public view returns (bool) { return raised >= goal; } function donate() public payable notFinished { uint refund; raised += msg.value; if (raised > goal) { refund = raised - goal; raised -= refund; msg.sender.transfer(refund); } emit Donated(msg.value); } function withdraw() public onlyOwner isFinished { uint amount = address(this).balance; owner.transfer(amount); emit Withdrew(amount); } } 

العقد جاهز سننشر عقدًا ذكيًا من خلال الترحيل.

عمليات الترحيل هي ملفات JavaScript تساعدك في نشر العقود على شبكة Ethereum. هذه هي الطريقة الرئيسية لنشر العقود.

انتقل إلى دليل التمويل -> دليل عمليات الترحيل وقم بإنشاء ملف 2_funding.js ، بإضافة التعليمة البرمجية التالية إليه:

 const Funding = artifacts.require("./Funding.sol"); const ETHERS = 10**18; const GOAL = 20 * ETHERS; module.exports = function(deployer) { deployer.deploy(Funding, GOAL); }; 

لتشغيل الاختبارات ، تحتاج إلى استخدام أمر اختبار الكمأة . في الجهاز ، انتقل إلى جذر دليل التمويل ، الذي تم إنشاؤه أثناء إعداد بيئة الاختبار وأدخل:

 truffle test 

إذا ظهر المخرج التالي في الجهاز ، فسيتم كل شيء بشكل صحيح:

الصورة

الآن لنبدأ في كتابة الاختبارات.

التحقق من المالك



انتقل إلى دليل التمويل -> اختبار وإنشاء ملف test_funding.js بالملحق .js . هذا هو الملف الذي سيتم فيه كتابة الاختبارات.

أضف التعليمات البرمجية التالية إلى ملف test_funding.js :

 const Funding = artifacts.require("Funding"); require("chai").use(require("chai-bignumber")(web3.BigNumber)).should(); contract("Funding", function([account, firstDonator, secondDonator]) { const ETHERS = 10**18; const GAS_PRICE = 10**6; let fundingContract = null; it("should check the owner is valid", async () => { fundingContract = await Funding.deployed(); const owner = await fundingContract.owner.call() owner.should.be.bignumber.equal(account); }); 

في الاختبار ، نتحقق من أن عقد التمويل يخزن عنوان المالك الذي نشر العقد. في حالتنا ، الحساب هو العنصر الأول للصفيف. Truffle يسمح لك باستخدام ما يصل إلى عشرة عناوين ، في الاختبارات نحتاج إلى ثلاثة عناوين فقط.

قبول التبرعات والتحقق من نهاية جمع التبرعات


في هذا القسم سوف نتحقق من:

  1. قبول وكمية التبرعات.
  2. وقد تم التوصل إلى مبلغ معين من التبرع.
  3. ماذا يحدث إذا تبرعت بأكثر مما تحتاج لجمعه.
  4. المبلغ الإجمالي للتبرع.
  5. هل يمكنني الاستمرار في جمع الأموال إذا تم جمع المبلغ المطلوب.

سنكتب ونحلل الاختبارات:

 . . . . . . . . . . . . . . . . . . . . . . const ETHERS = 10**18; const GAS_PRICE = 10**6; let fundingContract = null; let txEvent; function findEvent(logs, eventName) { let result = null; for (let log of logs) { if (log.event === eventName) { result = log; break; } } return result; }; it("should accept donations from the donator #1", async () => { const bFirstDonator= web3.eth.getBalance(firstDonator); const donate = await fundingContract.donate({ from: firstDonator, value: 5 * ETHERS, gasPrice: GAS_PRICE }); txEvent = findEvent(donate.logs, "Donated"); txEvent.args.donation.should.be.bignumber.equal(5 * ETHERS); const difference = bFirstDonator.sub(web3.eth.getBalance(firstDonator)).sub(new web3.BigNumber(donate.receipt.gasUsed * GAS_PRICE)); difference.should.be.bignumber.equal(5 * ETHERS); }); 

قبل تحليل الاختبار ، أريد ملاحظة نقطتين:

  1. للبحث عن الأحداث (الأحداث) والتحقق من الوسائط الخاصة بها ، تمت كتابة دالة findEvent صغيرة.
  2. لراحة الاختبار والحسابات ، تم تعيين القيمة الجوهرية للغاز (ثابت GAS_PRICE).

الآن دعونا نحلل الاختبار. في الاختبار ، فحصنا:

  • يمكننا قبول التبرعات عن طريق استدعاء طريقة التبرع () ؛
  • أن المبلغ المتبرع به لنا مبين بشكل صحيح ؛
  • أن الشخص الذي تبرع الأموال ، انخفض الرصيد بمقدار المبلغ المتبرع به.

 it("should check if donation is not completed", async () => { const isFunded = await fundingContract.isFunded(); isFunded.should.be.equal(false); }); 

في هذا الاختبار ، تحققنا من أن جمع التبرعات لم يكتمل بعد.

 it("should not allow to withdraw the fund until the required amount has been collected", async () => { let isCaught = false; try { await fundingContract.withdraw({ gasPrice: GAS_PRICE }); } catch (err) { isCaught = true; } isCaught.should.be.equal(true); }); 

في الاختبار ، فحصنا أنه لا يمكننا سحب الأموال حتى يتم جمع المبلغ الذي نحتاجه.

 it("should accept donations from the donator #2", async () => { const bSecondDonator= web3.eth.getBalance(secondDonator); const donate = await fundingContract.donate({ from: secondDonator, value: 20 * ETHERS, gasPrice: GAS_PRICE }); txEvent = findEvent(donate.logs, "Donated"); txEvent.args.donation.should.be.bignumber.equal(20 * ETHERS); const difference = bSecondDonator.sub(web3.eth.getBalance(secondDonator)).sub(new web3.BigNumber(donate.receipt.gasUsed * GAS_PRICE)); difference.should.be.bignumber.equal(15 * ETHERS); }); 

في الاختبار ، تحققنا من أنك إذا تبرعت بمبلغ كبير ، فإن طريقة التبرع () تحسب وتعيد الأموال إلى الشخص الذي تبرع بأكثر من اللازم. هذا المبلغ هو الفرق بين المبلغ المتراكم والمبلغ الذي تريد تحصيله.

 it("should check if the donation is completed", async () => { const notFunded = await fundingContract.isFunded(); notFunded.should.be.equal(true); }); it("should check if donated amount of money is correct", async () => { const raised = await fundingContract.raised.call(); raised.should.be.bignumber.equal(20 * ETHERS); }); it("should not accept donations if the fundraising is completed", async () => { let isCaught = false; try { await fundingContract.donate({ from: firstDonator, value: 10 * ETHERS }); } catch (err) { isCaught = true; } isCaught.should.be.equal(true); }); 

في هذه الاختبارات الثلاثة ، فحصنا:

  • اكتمال جمع التبرعات ؛
  • أن مبلغ التبرع صحيح ؛
  • أنه لا يمكن لأي شخص آخر التبرع ، حيث تم الانتهاء من جمع التبرعات.

سحب الأموال


في القسم السابق من البرنامج التعليمي ، جمعنا المبلغ الذي نحتاجه ، والآن يمكن عرضه:

  . . . . . . . . . . . . . . . . . . . . . . it("should allow the owner to withdraw the fund", async () => { const bAccount = web3.eth.getBalance(account); const withdraw = await fundingContract.withdraw({ gasPrice: GAS_PRICE }); txEvent = findEvent(withdraw.logs, "Withdrew"); txEvent.args.amount.should.be.bignumber.equal(20 * ETHERS); const difference = web3.eth.getBalance(account).sub(bAccount); difference.should.be.bignumber.equal(await fundingContract.raised.call() - withdraw.receipt.gasUsed * GAS_PRICE); }); 

عن طريق استدعاء وظيفة السحب () ، قمنا بسحب أموال مالك العقد الذكي ، في حساب قضيتنا. ثم تحققنا من أننا سحبنا بالفعل المبلغ الذي احتجنا إليه. للقيام بذلك ، اكتب الفرق في الرصيد قبل وبعد سحب الأموال في الفرق الثابت. تتم مقارنة النتيجة مع مبلغ التبرعات مطروحًا منها رسوم المعاملة. كما ذكر أعلاه ، لراحة الاختبار والحسابات ، حددت سعري للغاز .

قم بإجراء الاختبارات الكتابية باستخدام أمر اختبار الكمأة . إذا تم كل شيء بشكل صحيح ، يجب أن تكون النتيجة كما يلي:

الصورة

النتيجة


حاولت وصف خطوات اختبار العقود الذكية بلغة بسيطة ومفهومة: من إعداد بيئة اختبار إلى كتابة الاختبارات بأنفسهم.

يمكنك الآن اختبار أي عقد ذكي والتأكد من أنه يعمل بشكل صحيح.

Source: https://habr.com/ru/post/ar432012/


All Articles