티스토리 뷰
Foundry는 Solidity를 사용해 테스트를 작성합니다. 이 점에서 Javascript를 사용해야 하는 Truffle, Hardhat같은 툴체인과 차별점이 있습니다. 일반적으로 테스트는 'test' 디렉터리에 저장되며, '.t.sol' 확장자를 가집니다. 테스트 함수가 revert되면 테스트는 실패하는 것이고, 그 반대에는 테스트가 성공한 것으로 간주됩니다.
테스트 예제
Foundry 테스트는 Forge 표준 라이브러리의 'Test' 컨트랙트를 사용하여 작성할 수 있습니다. Test 컨트랙트는 기본적인 로깅과 어설션(assertion)을 제공합니다.
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
contract ContractBTest is Test {
uint256 testNumber;
function setUp() public {
testNumber = 42;
}
function test_NumberIs42() public {
assertEq(testNumber, 42);
}
function testFail_Subtract43() public {
testNumber -= 43;
}
}
코드의 중요한 부분을 나누어 설명하면 다음과 같습니다.
1. Test 컨트랙트 불러오기
import "forge-std/Test.sol";
Test 컨트랙트는 Forge 표준 라이브러리에서 불러올 수 있습니다.
2. Test 컨트랙트 상속
contract ContractBTest is Test {
...
}
Test 컨트랙트를 상속하여 테스트를 위해 정의된 함수들을 사용할 수 있습니다.
3. setUp 함수를 통해 테스트 환경 설정
function setUp() public {
testNumber = 42;
}
setUp 함수는 선택적으로 작성하는 함수이며, 각 테스트 케이스가 실행되기 전에 실행됩니다.
4. test로 시작하는 함수를 통해 테스트 작성
function test_NumberIs42() public {
assertEq(testNumber, 42);
}
test로 시작하는 함수는 실패해서는 안되는 긍정 케이스에 대한 테스트입니다.
5. testFail로 시작하는 함수를 통해 실패하는 테스트 작성
function testFail_Subtract43() public {
testNumber -= 43;
}
testFail로 시작하는 함수는 test로 시작하는 함수와 반대로, 성공해서는 안되는 부정 케이스에 대한 테스트입니다.
6. 테스트 함수를 작성하는 좋은 습관
test_Revert[If | When]_Condition 패턴과 expectRevert cheatcode를 조합하여 테스트 함수를 작성하는 것이 더 직관적인 테스트를 작성하는 좋은 습관입니다. 예를 들어, testFail_Subtract43보다는 testNumber에서 43을 뺐을 때 예상되는 오류를 expectRevert로 명시해주고 함수명을 test_CannotSubtract43으로 변경하여 uint256 타입의 값 42에서 43을 뺄 수 없음을 나타내는 것이 더 이해하기 쉽고 좋은 테스트라고 할 수 있습니다.
function test_CannotSubtract43() public {
vm.expectRevert(stdError.arithmeticError);
testNumber -= 43;
}
7. 테스트 컨트랙트의 배포
테스트는 로컬에서 간단한 배포 과정을 거칩니다. 이 때 모든 테스트는 '0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84' 주소로 배포됩니다. 만약 테스트 안에서 컨트랙트를 배포한다면 배포자는 '0xb4c7...7e84'가 됩니다. 따라서 배포된 컨트랙트에 대한 권한이 '0xb4c7...7e84'에게 부여됩니다. 예를 들어, 컨트랙트 배포자만 호출할 수 있는 함수를 '0xb4c7...7e84'가 호출할 수 있게 되는 것입니다.
테스트 함수는 반드시 external 또는 public 접근자로 선언되어야 합니다. internal과 private 접근자는 Forge가 인식하지 못합니다.
설정 공유
헬퍼 추상 컨트랙트를 생성하고 상속함으로써 설정값을 공유할 수 있습니다. (실제 값이 공유되지는 않음)
abstract contract HelperContract {
uint256 testNumber;
}
contract MyContractTest is Test, HelperContract {
function setUp() public {
testNumber = 42;
}
function test_NumberIs42() public {
assertEq(testNumber, 42);
}
}
contract MyOtherContractTest is Test, HelperContract {
function setUp() public {
testNumber = 43;
}
function test_NumberIs43() public {
assertEq(testNumber, 43);
}
}
📖 참고자료
글에서 수정이 필요한 부분이나 설명이 부족한 부분이 있다면 댓글로 남겨주세요!
'Solidity > Foundry' 카테고리의 다른 글
Foundry 프로젝트에서 Hardhat 같이 사용하기 (0) | 2024.04.21 |
---|---|
[Foundry] .env 파일 사용하지 마세요 (0) | 2024.02.23 |
Inline Assembly를 사용해 ERC-20 구현하기 & Inline Assembly 활용하기 (1) | 2024.02.17 |
Foundry 프로젝트 살펴보기 (1) | 2023.10.27 |
Foundry 설치 (0) | 2023.10.22 |