Truffle测试Solidity合约时报_character.getName非函数错误
问题描述
执行truffle test命令运行智能合约测试用例时,触发如下报错:
TypeError: _character.getName is not a function
测试预期逻辑:部署Game合约后调用createCharacter方法创建角色,通过getCharacter获取角色合约地址,实例化Character合约后调用getName方法校验角色名是否和传入参数一致。
环境信息
- Truffle v5.5.20 (core: 5.5.20)
- Ganache v7.2.0
- Solidity - 0.8.15 (solc-js)
- Node v16.15.1
- Web3.js v1.7.4
相关代码
测试文件代码
let Game = artifacts.require("./Game.sol"); let Character = artifacts.require("./Character.sol"); const PROVIDED_NAME = "TEST"; contract("Game", (accounts) => { let creatorAccount = accounts[0]; it("should create a character with the name provided", () => { let _game; let _character; return Game.deployed() .then(instance => { _game = instance; return _game.createCharacter(PROVIDED_NAME, { from: creatorAccount }); }) .then(result => { return _game.getCharacter(); }) .then(character => { _character = Character.at(character); return _character.getName(); }) .then(name => { assert.equal(name, PROVIDED_NAME, "Failed to create a character with the provided name"); }); }); });
Character.sol合约代码
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; contract Character { string private _name; constructor(string memory name) public { _name = name; } function getName() public view returns (string memory) { return _name; } }
排查解决步骤
- 第一步:校验
getCharacter()返回值格式
这是该报错最常见的诱因。Truffle v5调用合约view/pure方法时,即使方法只返回单个值,也会返回一个带索引的类数组结果对象,而非直接返回值本身。你可以在获取character的回调中加console.log(character)打印返回内容,如果输出类似Result { '0': '0x.....' }的结构,说明你直接把整个结果对象传入了Character.at(),而非实际的地址字符串,自然无法得到正确的合约实例、找不到getName方法。
修正对应代码段,取结果的第一个索引位作为地址即可:.then(character => { // 取返回结果的第一个值,即实际的角色合约地址 const characterAddr = character[0]; _character = Character.at(characterAddr); return _character.getName(); }) - 第二步:校验Game合约的逻辑正确性
确认Game合约中两个方法的实现符合预期:createCharacter方法中确实通过new Character(name)的方式创建了Character合约实例,且将实例地址正确存入了合约状态变量getCharacter方法的返回值类型为address,返回值为前述存储的Character合约地址,没有返回零地址或其他不相关的状态变量
- 第三步:修正Character合约的构造函数兼容问题
Solidity 0.7.0及以上版本中,构造函数无需显式声明public可见性,保留该写法虽然不会直接触发当前报错,但可能在后续编译、部署环节触发异常,建议修改为:constructor(string memory name) { _name = name; } - 第四步:验证合约实例有效性
实例化_character后,可以打印_character对象确认其是否挂载了getName方法,如果方法不存在,优先回到第一步检查传入的地址是否为合法的20字节EVM地址字符串。
内容的提问来源于stack exchange,提问作者Taki Eddine Abdesselam
相关产品推荐
相关产品推荐

