title | actions | requireLogin | material | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
转移僵尸 |
|
true |
|
提问 —— 假如 Alice 想把她的僵尸发送给 Bob. 我们要对其测试吗?
当然!
如果你一直有上前面的课,那么你应该知道,我们的僵尸继承自 ERC721。ERC721 规范有两种不同的方法来转移代币:
(1)
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
第一种方法是 Alice(其主人)调用 transferFrom
,她的 address
作为 _from
参数,Bob 的 address
作为 _to
参数,以及她想要转移的 zombieId
。
(2)
function approve(address _approved, uint256 _tokenId) external payable;
然后
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
第二种方法是, Alice 首先用 Bob 的地址和 zombieId
调用 approve
。然后,合约存储了批准 Bob 带走僵尸的信息。接下来,当 Alice 或 Bob 调用 transferFrom
时,合约检查该 msg.sender
是否等于 Alice 或 Bob 的地址。如果是,它将把僵尸转移给 Bob。
我们将这两种转移僵尸的方式称为“场景”。为了测试每个场景,我们需要创建两个不同的测试组,并为它们有意义的描述。
为什么给它们分组?我们只有不多几个测试啊……
是的,现在我们的逻辑很简单,但情况并不总是这样。第二种场景(即 transferFrom
之前的 approve
)依然需要至少两个测试:
-
首先,我们必须检查 Alice 自己是否能够转移僵尸。
-
其次,我们还要检查是否允许 Bob 运行
transferFrom
。
此外,以后你可能想添加需要不同测试的其他功能。我们认为最好是从一开始就设置一个可扩展结构 😉。让其他人更容易理解你的代码,也让过了很久之后的你自己更容易理解。
注意:如果后来你与其他程序员一起合作,你会发现他们更有可能遵循你在初始代码中制定的任何约定。如果你想做成一个大项目,有效的合作是你需要的关键技能之一。有了这些能帮助你尽早实现的良好习惯,你的程序员生涯会更轻松、也会走得更远。
对测试进行分组, Truffle 提供了一个叫做 context
的函数。来看看如何使用它来更好地组织我们的代码:
context("with the single-step transfer scenario", async () => {
it("should transfer a zombie", async () => {
// TODO: Test the single-step transfer scenario.
})
})
context("with the two-step transfer scenario", async () => {
it("should approve and then transfer a zombie when the approved address calls transferForm", async () => {
// TODO: Test the two-step scenario. The approved address calls transferFrom
})
it("should approve and then transfer a zombie when the owner calls transferForm", async () => {
// TODO: Test the two-step scenario. The owner calls transferFrom
})
})
如果我们把这个添加到我们的 CryptoZombies.js
文件,然后运行 truffle test
,输出会像这样:
Contract: CryptoZombies
✓ should be able to create a new zombie (100ms)
✓ should not allow two zombies (251ms)
with the single-step transfer scenario
✓ should transfer a zombie
with the two-step transfer scenario
✓ should approve and then transfer a zombie when the owner calls transferForm
✓ should approve and then transfer a zombie when the approved address calls transferForm
5 passing (2s)
呃...
再看一下 —— 上面的输出有个问题。看起来所有的测试都通过了,这显然是错误的,因为我们根本就还没有写它们!!
幸好,有一个简单的解决方案 —— 如果我们在 context()
函数前面加上一个 x
,像这样:xcontext()
,那么 Truffle
将跳过那些测试。
注意:
x
也可以放在it()
函数前面。当编写完这些函数的测试时,不要忘记删除所有的 x 哦!
现在,我们来运行 truffle test
。输出会像这样:
Contract: CryptoZombies
✓ should be able to create a new zombie (199ms)
✓ should not allow two zombies (175ms)
with the single-step transfer scenario
- should transfer a zombie
with the two-step transfer scenario
- should approve and then transfer a zombie when the owner calls transferForm
- should approve and then transfer a zombie when the approved address calls transferForm
2 passing (827ms)
3 pending
其中“-”表示使用了“x”标记跳过的测试。
很厉害,对吧?现在你可以一边运行测试,一边标记出不久之后需要编写测试的空函数。
-
复制/粘贴上面的代码。
-
我们暂时先 跳过
context
新函数。
我们的测试只是空 shell,为了实现它们需要编写大量的逻辑。在接下来的章节中,我们将分段讲解。