Solidity

為什麼 Truffle 的測試框架不會在每次與合約互動後自動檢索公共狀態變數的新值?

  • January 9, 2022

我定義了以下簡單的智能合約:

contract LoanApplication {

 struct Applicant {
   bytes32 ssn;
   bool hasApplied;

 }

 struct Loan {
   string loanID;
   uint applicantCount;
   uint256 rate;
   uint term;
 }

mapping (address => Applicant) public applicants;

Loan[] public loans;

address public loansAdmin;

constructor(string[] memory loanIDs) {

   loansAdmin = msg.sender;

  for (uint i=0; i < loanIDs.length; i++) {
       // Create Loan object and append to loans array
       loans.push(Loan({
           loanID: loanIDs[i],
           applicantCount:0,
           rate: 10,
           term: 30
           }));
   }

}

function receiveApplication(address applicant) external {
   require(
       msg.sender == loansAdmin, "Only administrator can receive application"
       );

    require(
       !applicants[applicant].hasApplied,
       "Applicant previously applied"
       );

   applicants[applicant].hasApplied = true;


  }

}

這是我的 Javascript 測試:

const LoanAppContract = artifacts.require("LoanApplication");

contract("LoanApplicationTest", accounts => {


   const loanIDs = ["Loan1", "Loan2", "Loan3"];


   beforeEach (async () =>  {
      loanApp = await LoanAppContract.new(loanIDs);
   });
    describe("initialization", () => {
       ...


     });



    describe("register application",() => {
       it("receive app",  async() => {


         let applicantAddr = accounts[1]; 
         console.log("applicantAddr=" + applicantAddr);

         let applicant = await loanApp.applicants(applicantAddr);


         assert.isTrue(!applicant.hasApplied);


         await loanApp.receiveApplication(applicantAddr, {from: accounts[0]});


         let applicantRefreshed = await loanApp.applicants(applicantAddr);

         //assert.isTrue(applicant.hasApplied);

         assert.isTrue(applicantRefreshed.hasApplied);


   });

 });

});

我正在嘗試測試契約中的 receiveApplication 函式。貸款管理員hasApplied在應用程序對象 corr 中設置標誌。到傳入的地址為真

我的問題是針對這些行:

// Obtain applicant 
let applicant = await loanApp.applicants(applicantAddr);

// Verify that hasApplied is set to false
assert.isTrue(!applicant.hasApplied);

現在呼叫 receiveApplication 函式。hasApplied 標誌現在設置為 true

await loanApp.receiveApplication(applicantAddr, {from: accounts[0]});

我的問題是這樣的:

為什麼這個測試失敗了?

我期待著

assert.isTrue(applicant.hasApplied)

成功,表明 hasApplied 是真的,但看起來申請人參考是陳舊的?

相反,我必須做

let applicantRefreshed = await loanApp.applicants(applicantAddr);
assert.isTrue(applicantRefreshed.hasApplied);

為測試成功。我對 Solidity 和 Javascript 還很陌生——迄今為止,我一直是一名 Python 和 Java 開發人員。

感謝幫助澄清這一點。

我正在使用松露執行我的測試,謝謝

本質上是因為您已經在使用一個抽象層,它可以在您需要時為您提供所需的東西,並在呼叫時為您提供的值。由合約的抽象實例(loanApp在您的情況下)在幕後工作,通過 RPC 呼叫節點以了解狀態並將結果發回給您。這就是為什麼您需要await並且您不能及時使用該值的原因。

智能合約可以由開發人員應用程序/測試環境在外部進行修改,因此嘗試保持某種實時同步並非易事。例如,您可以嘗試Drizzle來執行此操作,但無論如何,它專用於 UI,而不是測試和開發階段。

無論如何,如果您想要一個更簡潔的語法而不需要使用許多臨時變數,您可以編寫如下內容:

let applicantAddr = accounts[1]; 
console.log("applicantAddr=" + applicantAddr);
assert.isTrue(!(await loanApp.applicants(applicantAddr)).hasApplied);
await loanApp.receiveApplication(applicantAddr, {from: accounts[0]});
assert.isTrue((await loanApp.applicants(applicantAddr)).hasApplied);

引用自:https://ethereum.stackexchange.com/questions/118381