Foundryとスマートコントラクトのユニットテスト

皆さん、Foundryをご存じですか？これは昨今人気急上昇中の、Solidityで開発を行ったりユニットテストを記述できる開発フレームワークになります。本記事ではFoundryの中のテスト機能に焦点を当てて紹介していきます。

まず、SolidityとはEthereumブロックチェーンのスマートコントラクトを記述するときに使用される主要言語です。

スマートコントラクトは、任意の関数や変数等を記述してEthereum Virtual Machineに指示された処理を実行させ、それによってブロックチェーン上の状態（ステート）を変更させる事のできるプログラムと言えます。

Ethereumではこれまでスマートコントラクトのテストの記述はJavaScriptをベースとした開発者ツールを用いる事が常でした。HardhatやTruffleなどと呼ばれるツールですね。

その為、スマートコントラクトをSolidityで記述しながらテストはJavaScriptで書くという言語を跨いだ「脳内スイッチング」作業が必須でした。それがFoundryの登場により,
希望する開発者はこの脳内スイッチング作業から解放されることになります。

そのFoundryですが、使い方はいたって簡単。予め準備されている”Test.sol”というファイルを個別のテストファイルにインポートして継承するだけです。

以下の例では”ContractBTest”が準備中のテストコントラクト、そして”is Test”の箇所で上述の事前準備されている”Test.sol”ファイルを作成中の”ContractBTest”に継承させています。

![i1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/4e850306-5d76-8488-98cf-4c56b9d46ed2.png)
出典：Foundry Book https://book.getfoundry.sh/forge/writing-tests、ハイライトは筆者

ここから先はビルトインされているキーワードを使用してテストします。例えば
上記の例ではsetUp()関数内にて”testNumber = 42”と記述することで、テストの値を一旦42に設定しています。

その上で本当にテストの値が42に設定されているかどうか、つまりは「等しさ」を確認するべく

”assertEq(testNumber,  42)”

と記述。”assertEq”のEqはEqualの略、つまり等しさの英語表記で”assert”は主張の意なので提示された2つの値が等しいことを主張する関数ですね。

この機能を応用すると、トークンの供給量が値Xに等しいことを確認したい場合に”assertEq”を用いて2つの値が等しいことをテストする、といった利用が可能となります。

他にも、特定の関数がコントラクトの所有者以外は呼べない状態であるかを確認したいとします。

![i2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/0889887b-c85b-29e0-d13c-8b29274d13d6.png)
出典：Foundry Book　https://book.getfoundry.sh/forge/cheatcodes　ハイライトは筆者

上記のコントラクトは、当該コントラクトの所有者しかincrement関数を呼ぶことが出来ず、呼ばれた回数がカウントされる作りになっています。


![i3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/ae54b9da-22b2-91c3-a557-9ded1e3a1041.png)

出典：Foundry Book　https://book.getfoundry.sh/forge/cheatcodes　ハイライトは筆者

ハイライト箇所のvmはCheatcodeと呼ばれるもので多数のテスト用メソッドが用意されています。prankはその一つで次に関数をコールする際のコール元アドレスを架空のものに設定する事が可能です。

つまり、vm.prank(address(0))を用いる事でテストの実行者は外部アカウントを実際に作成する手間をかける事なく仮想アカウントの所有者になりすまし、テスト対象の関数をコールする事が可能になります。この架空のアドレスは当該コントラクトの所有者アドレスとは異なるため、当該コールが当初の設計通り失敗する事を期待するテストになります。

結果、以下の様にテストは無事PASSとなっています。

![i4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/64a36ee5-ab09-4234-6f42-5387ffabfeef.png)

出典：Foundry Book　https://book.getfoundry.sh/forge/cheatcodes　ハイライトは筆者

この上記の画像に表示されている実行内容の詳細はFoundryではTraceと呼ばれており、失敗したテストは-vvvで、成功したテストも含めた全てのテストについては-vvvvとコマンドを打つことで見られるようになっています。

ここまでは主にFoundryを使用したユニットテストについて述べてきましたが、他にもFoundryではFuzzテストを実行する事が可能です。Fuzzテストとは、平たくいうと関数等の特定のパラメータがインプットの値によってエラーを起こさないか確認するためのテストになります。例えば、基準を超えた金額が引き出されないかどうかを確認したい時に多数のテスト値を用いてテストを実行し、考慮漏れの有無等を確認してくれます。

Fuzzテストはあらゆるテストの中でも自動化に最も向いている分野の1つであり、今後もブロックチェーンに実装されるスマートコントラクトの数が増加の一途を辿るであろうことを念頭に置くとこのFuzzテストの実装の有無、またその巧拙が将来の開発者ツールの行方を決める大きな要因の1つになると言っても過言ではないでしょう。

この他にも冒頭のContractBTestにあるsetup()関数内でフォークを作成しそのフォークさせたチェーンでテストを実行できたり、Foundry自体がRustで記述されているためテストの実行スピード自体も速くなっています。コントラクトの内容にもよりますが従来のテストツールと比較して2分の1から3分の1程度の所用時間でテストが完了するケースがままあるようです。

この様にFoundryはベーシックなものからハイレベルなものまで嬉しい機能が揃っていて利便性も高く、Solidityのファンにとっては何から何までSolidityで完結する嬉しいツールと言えるでしょう。

ここでは全てを紹介しきれませんでしたが他にもいろんな便利な機能がついているので、時間があればぜひFoundryのウェブサイトをチェックしてみて下さい。

https://book.getfoundry.sh/

クリプトに熱い方とお仕事が出来る事を楽しみにしています！


最後に、弊社bitFlyerでは[エンジニアを募集](https://bitflyer.com/ja-jp/recruit)しています。ご興味のある方はぜひご応募ください！