Forge详细教程

Forge是一个以太坊开发框架。您可以使用它来创建Solidity项目,管理依赖关系,运行测试等等。它受Dapp启发,与之有一个重要的相似之处,即测试是用Solidity编写的。这与迄今为止的其他以太坊开发框架不同。它是用Rust编写的,非常快速。

这是一个初学者指南。我将介绍如何创建项目,管理依赖项和编写测试。预期的受众是熟悉Solidity并希望了解如何使用Forge进行开发的人。

开始

首先,您需要安装Foundty的以太坊工具包。我建议查看仓库以获取最新的安装说明,但这是当前的安装命令。

$ cargo install --git https://github.com/gakonst/foundry --bin forge --locked

请注意,如果您尚未安装Rust/Cargo,则需要先安装它。请查看这里的说明
(Forgeup是一个有用的工具,用于获取最新的Forge版本或指向特定分支。)

接下来,创建一个文件夹进行操作,并初始化一个项目。

$ mkdir forge-tutorial
$ cd forge-tutorial
$ forge init

Nice!现在在forge-tutorial目录下应该有两个目录:libsrc

lib目录是所有安装的依赖项所处的位置。这些依赖项是作为git子模块进行管理的。您会发现在lib目录中已经有一个名为ds-test的依赖项,默认已经安装好了。ds-test是由Dapp的创建者开发的,其中包含了一些用于测试的有用的函数和事件的合约。您可以在Github上看到这个代码。

src目录是您的代码所在的位置。在顶层您会看到Contract.sol和一个test目录。在test目录中有Contract.t.sol

测试

由于这份文档是针对那些已经熟悉Solidity的人群,我将主要关注于测试,因为这正是在使用Forge时的独特之处。

开始

运行forge test,您应该会看到类似这样的内容。

image.png
测试通过,并告诉您测试函数使用的 gas 量。

让我们打开Contract.t.sol文件,看看发生了什么。

image.png
首先,您应该注意到我们在用Solidity编写测试!许多人已经习惯了用其他语言为Solidity编写测试,但当您考虑这一点时,这似乎有点奇怪。您能想到其他需要您使用不同语言来测试代码的编程语言吗?这是Forge的创作者的一个重要观点:如果每个Solidity开发者都必须同时了解其他语言,我们怎样才能培养出优秀的Solidity开发者呢?

让我们深入研究一下正在发生的事情。首先,我们注意到在顶部导入了ds-test,合约正在继承自DSTest,这就给ContractTest提供了访问ds-test/test.sol中所有方便的测试函数/事件的权限,正如我上面所提到的。例如,正在使用的assertTrue函数是在DSTest中定义的。我建议您查看ds-test文件夹中的test.sol文件,看看所有可用的不同类型的断言。

setUp是一个特殊的函数,在任何测试运行之前将被调用。稍微修改代码以查看其运行原理。

image.png

如果您运行forge test,这个测试应该通过。

将数字10改为9

image.png
然后运行forge test,您应该会看到结果。

image.png
Nice!如预期一样,测试失败了。请注意,测试函数的名称必须包含test。如果函数只是叫做example,它不会自动在运行forge test时执行。

如果您期望测试失败,您可以将测试名称的前缀改为testFail,而不仅仅是test

image.png
如果您运行forge test,这个测试应该会通过。请注意,这也适用于回滚操作。

image.png
实际上,我也认为testFail模式有点奇怪(您知道有东西失败了,但不知道具体是什么)。在下面的“Cheat Codes”中,我们将讨论一个更好的选择,即expectRevert

要实际测试您的智能合约,首先我们需要在Contract.sol中添加一些代码。

image.png
然后在Contract.t.sol中,您可以导入这个合约,并像下面这样为其编写一个测试:

image.png

日志记录和跟踪

在运行测试时,您可以通过传递-v来指定详细程度。更多的-v,详细程度越高,5(-vvvvv)是最高级别。以下是每个级别的作用:

1: 默认(在运行测试时通常看到的结果)
2: 打印日志
3: 为失败的测试打印测试跟踪
4: 总是打印测试跟踪,为失败的测试打印设置
5: 总是打印测试跟踪和设置

让我们添加一行日志并使用-vv来运行我们的测试,以查看它。 我将在我的代码中添加一个 emit log_string
如果您对Solidity不太熟悉,合约可以发出事件。但是log_string事件在哪里定义的呢?在ds-test库中的test.sol文件中。

image.png
运行forge test -vv

image.png
查看test.sol中的其他日志事件,并尝试一些其他的事件!接下来,让我们传入-vvvv,这样我们就可以看到来自我们测试的详细信息。运行forge test -vvvv

image.png
这向您展示了我们的测试函数testAddone 调用了addOne,addOne 调用使用了717 gas,并返回了3!

Fuzzing

Forge的一个非常酷炫的功能是模糊测试。与指定函数的静态输入不同,模糊测试会为您提供特定类型的随机值。例如,我们可以通过更改函数以接受一个参数来将testAddOne制作成一个模糊测试,就像这样

image.png
如果您运行forge test,会看到

image.png
这段文字告诉您它运行了256次(每次使用随机的uint256值x),平均gas是2789,中位数是2791。

Cheat Codes

作弊码是使用Forge进行测试的基础。 作弊码存在于Dapp中,并在Forge中得到拓展。 基本上,这些作弊码是对“VM”合约的调用,会导致VM修改其普通执行行为。 我在这里给出几个例子。

首先,让我们谈谈作弊码,它可以用来设置下一次调用的msg.sender。 如果这听起来没有意义,只需要继续阅读,您就会明白我的意思。

首先,我将在Contract.t.sol的顶部添加一个合约。

image.png

接下来更新我们的测试合约

image.png
注意,我可以简化这个操作为

image.png
我正在尝试构建setUp的使用,这对于更复杂的设置是必需的。

现在,我们需要添加一个接收作弊码调用的VM合约。

image.png
该VM始终位于这个地址。它是从哪里来的呢?address(bytes20(uint160(uint256(keccak256(‘hevm cheat code’))))) = 0x7109709ecfa91a80626ff3989d68f67f5b1dd12d。我们还需要定义一个VM接口,以便编译器知道我们希望能够调用哪些方法。你可以添加任意数量的作弊码,现在我将添加prank。

image.png
最后,让我们将我的测试更新为命名为testBar,并调用 foo.bar()。我的测试文件现在看起来像这样。

image.png
运行forge test -vvvv 你会看到

image.png
这里发生了什么呢?嗯,bar 要求 msg.sender 是 address(1),但当前的 msg.sender 只是我们测试合约的地址。我们可以使用 prank 从 address(1) 调用 bar。

image.png
运行forge test -vvvv

image.png
现在,我们还可以使用另一个作弊码 expectRevert 来测试我们预期的 revert。将 expectRevert 添加到 Vm 接口中。

image.png
然后增加一个新的测试

image.png
运行forge test -vvvv

image.png
Nice!

添加依赖

假设我们想要使用其他人的合约。也许是来自 Rari 的 Solmate。我们可以通过运行 forge install rari-capital/solmate 来进行安装。运行此命令后,你会看到 solmate 已经被添加到 lib 中。

我可以像这样导入特定的合约:

image.png

Remappings

你的一些合约或你导入的合约可能在 NPM 格式中有导入,例如 import "@openzeppelin/contracts/access/Ownable.sol;。让我们看看如何处理这种情况。

首先安装 OpenZeppelin 合约:forge install OpenZeppelin/openzeppelin-contracts

接下来,让我们将该导入行添加到我们的测试文件中。

image.png
运行forge build

image.png
我们可以通过创建一个 remappings.txt 文件来告诉 Forge 正确查找这个文件的位置。

$ touch remappings.txt

然后在该文件写入:

@openzeppelin/=lib/openzeppelin-contracts/

这告诉 Forge:“嘿,每当你遇到 @openzepplin/,就在 lib/openzeppelin-contracts/ 中查找。”

现在如果你运行 forge buildforge test,应该可以正常工作。

高级测试

匹配标志

如果你只想运行一些测试,有一个很方便的标志 -m,它会匹配测试名称。例如,运行 forge test -vvvv -m Revert,任何测试名称中包含“Revert”的测试都会运行!

快照

通过运行 forge snapshot 来快照你的测试的 gas 使用情况。

Fork模式

与从空白状态开始不同,你可以使用来自实时以太坊网络的状态来运行你的测试。要做到这一点,你需要使用 -f 标志将以太坊节点 URI 传递给你的测试,即 forge test -f <uri>。(你可以从 Alchemy 或 Infura 获取这样的 URI。)这非常酷:在你的测试中,你可以调用一个地址,比如 Mainnet 上的 USDC 地址,并获得实时网络状态的响应。这对于测试可能特别难以模拟的合约或状态非常有用。

再见

如有任何问题,请随时直接私信。

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
对于Electron集成ExtJS的详细教程,以下是一个简单的步骤指南: 步骤1:创建Electron项目 首先,你需要创建一个Electron项目。可以通过使用Electron提供的命令行工具(electron-forge、electron-builder等)或手动创建一个基本的Electron项目。 步骤2:下载ExtJS框架 前往Sencha官方网站下载ExtJS框架。选择适合你的版本,并下载压缩包。 步骤3:解压缩ExtJS框架 将下载的ExtJS压缩包解压到你的Electron项目的目录中。确保将其放置在一个易于访问的位置。 步骤4:引入ExtJS库 在你的Electron项目的index.html文件中,使用script标签引入ExtJS库。根据你的文件结构和解压位置,设置正确的路径。 ```html <script src="path/to/extjs/ext-all.js"></script> ``` 步骤5:创建ExtJS应用 在你的Electron项目中创建一个新的JavaScript文件,用于编写ExtJS应用。在该文件中,编写ExtJS应用的代码逻辑。 ```javascript // 示例代码 Ext.application({ name: 'MyApp', launch: function () { Ext.create('Ext.panel.Panel', { title: 'Hello ExtJS!', width: 400, height: 300, renderTo: Ext.getBody() }); } }); ``` 步骤6:加载ExtJS应用 在Electron项目的主进程(main.js)中,使用BrowserWindow加载ExtJS应用的入口文件。 ```javascript // 示例代码 const { app, BrowserWindow } = require('electron'); const path = require('path'); function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } }); mainWindow.loadFile('path/to/your/extjs-application.js'); // 其他窗口逻辑... } app.whenReady().then(() => { createWindow(); }); ``` 步骤7:运行Electron应用 最后,通过运行你的Electron应用来启动集成了ExtJS的界面。 确保在Electron项目的根目录下运行以下命令: ```bash electron . ``` 以上是一个简单的详细教程,希望能对你有所帮助。根据你的具体需求和项目结构,还可能需要进行更多配置和调整。同时,建议参考ExtJS官方文档和Electron文档以获得更详细的信息和指导。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值