目录
1. truffle
https://truffleframework.org/docs/getting_started
(1)测试合约中获得部署地址: truffle/DeployedAddresses.sol
库 提供了 DeployedAddresses.<contract name>();
(2)所有测试合约明星必须以 Test
开头, 测试函数的名字以test开头;
(3)一般情况, 合约方法需要以交易的形式传递给 以太坊, 但是并不返回方法的结果, 而是返回一个交易的ID.
(4)写数据称为 transaction 交易, 而读数据称为 call 调用。交易:消耗gas, 改变网络状态,并不立即执行,返回交易ID;
调用:不消耗gas,不改变状态,立即执行,直接返回需要的值。
(5)commands: build, compile, create, debug, exec, install, migrate, networks, opcode, publish, test, version.
/contract 智能合约
pragma solidity ^0.4.2;
import "./ConvertLib.sol";
// 这只是货币合约的简单实现, 并非兼容标准, 也不能直接与其他货币/token合约交互.
// 如果想要创建兼容标准的token, 参考: https://github.com/ConsenSys/Tokens. 继续!
contract MetaCoin {
mapping (address => uint) balances;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
function MetaCoin() {
balances[tx.origin] = 10000;
}
function sendCoin(address receiver, uint amount) returns(bool sufficient) {
if (balances[msg.sender] < amount) return false;
balances[msg.sender] -= amount;
balances[receiver] += amount;
Transfer(msg.sender, receiver, amount);
return true;
}
function getBalanceInEth(address addr) returns(uint){
return ConvertLib.convert(getBalance(addr),2);
}
function getBalance(address addr) returns(uint) {
return balances[addr];
}
}
/migration 部署合约
var Migrations = artifacts.require("Migrations");
module.exports = function(deployer) {
// Deploy the Migrations contract as our only task
//Migrations构造函数需要参数时,需要添加参数;
deployer.deploy(Migrations);
};
/test测试合约:
1. 编写 .sol文件来测试
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/MetaCoin.sol";
contract TestMetacoin {
function testInitialBalanceUsingDeployedContract() {
MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin());
uint expected = 10000;
Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially");
}
function testInitialBalanceWithNewMetaCoin() {
MetaCoin meta = new MetaCoin();
uint expected = 10000;
Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially");
}
}
2 编写.js文件来测试
// 引入合约
var MetaCoin = artifacts.require("./MetaCoin.sol");
// 类似 describe, 返回账号列表
contract('MetaCoin', function(accounts) {
it("should put 10000 MetaCoin in the first account", function() {
return MetaCoin.deployed().then(function(instance) {
return instance.getBalance.call(accounts[0]);
}).then(function(balance) {
assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account");
});
});
it("should call a function that depends on a linked library", function() {
var meta;
var metaCoinBalance;
var metaCoinEthBalance;
return MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.getBalance.call(accounts[0]);
}).then(function(outCoinBalance) {
metaCoinBalance = outCoinBalance.toNumber();
return meta.getBalanceInEth.call(accounts[0]);
}).then(function(outCoinBalanceEth) {
metaCoinEthBalance = outCoinBalanceEth.toNumber();
}).then(function() {
assert.equal(metaCoinEthBalance, 2 * metaCoinBalance, "Library function returned unexpected function, linkage may be broken");
});
});
it("should send coin correctly", function() {
var meta;
// Get initial balances of first and second account.
var account_one = accounts[0];
var account_two = accounts[1];
var account_one_starting_balance;
var account_two_starting_balance;
var account_one_ending_balance;
var account_two_ending_balance;
var amount = 10;
return MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.getBalance.call(account_one);
}).then(function(balance) {
account_one_starting_balance = balance.toNumber();
return meta.getBalance.call(account_two);
}).then(function(balance) {
account_two_starting_balance = balance.toNumber();
return meta.sendCoin(account_two, amount, {from: account_one});
}).then(function() {
return meta.getBalance.call(account_one);
}).then(function(balance) {
account_one_ending_balance = balance.toNumber();
return meta.getBalance.call(account_two);
}).then(function(balance) {
account_two_ending_balance = balance.toNumber();
assert.equal(account_one_ending_balance, account_one_starting_balance - amount, "Amount wasn't correctly taken from the sender");
assert.equal(account_two_ending_balance, account_two_starting_balance + amount, "Amount wasn't correctly sent to the receiver");
});
});
});
与合约交互
发起交易:
var account_one = "0x1234..."; // 地址1
var account_two = "0xabcd..."; // 地址2
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.sendCoin(account_two, 10, {from: account_one});
}).then(function(result) {
// 执行此回调, 说明交易成功执行
alert("Transaction 交易成功!")
}).catch(function(e) {
// 执行此回调, 说明出现错误
})
发起调用
var account_one = "0x1234..."; // 一个地址
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.getBalance.call(account_one, {from: account_one});
}).then(function(balance) {
// 执行此回调, 说明调用成功执行. 注意: 这个方法会立即回调, 没有等待时间.
// 我们打印一下合约方法返回的余额
console.log(balance.toNumber());
}).catch(function(e) {
// 执行此回调, 说明出现错误
})
捕捉事件:
var account_one = "0x1234..."; // 地址1
var account_two = "0xabcd..."; // 地址2
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.sendCoin(account_two, 10, {from: account_one});
}).then(function(result) {
// result 是一个包含如下内容的对象:
//
// result.tx => 交易哈希值, 字符串
// result.logs => 解码后的事件内容列表
// result.receipt => 交易收据对象, 包含交易消耗的 gas 等
// 我们可以循环处理这些事件内容 (result.logs) 来检测是否我们触发了转账 (Transfer) 事件.
for (var i = 0; i < result.logs.length; i++) {
var log = result.logs[i];
if (log.event == "Transfer") {
// 我们找到了交易
break;
}
}
}).catch(function(err) {
// 执行此回调, 说明出现错误
});