diff --git a/test/TESTING.md b/test/TESTING.md index 321c7e592d6..79dbe382591 100644 --- a/test/TESTING.md +++ b/test/TESTING.md @@ -1,3 +1,116 @@ ## Testing Unit tests are critical to OpenZeppelin Contracts. They help ensure code quality and mitigate against security vulnerabilities. The directory structure within the `/test` directory corresponds to the `/contracts` directory. + +### Testing Framework + +OpenZeppelin Contracts uses [Hardhat](https://hardhat.org/) as its development and testing environment, along with [Mocha](https://mochajs.org/) as the test runner and [Chai](https://www.chaijs.com/) for assertions. + +### Running Tests + +To run the entire test suite: + +```bash +npm test +``` + +To run a specific test file: + +```bash +npx hardhat test test/path/to/test-file.js +``` + +To run tests with gas reporting: + +```bash +REPORT_GAS=true npm test +``` + +### Test Structure + +Tests are organized to mirror the contract directory structure. For example: +- Tests for `contracts/token/ERC20/ERC20.sol` are in `test/token/ERC20/ERC20.test.js` +- Tests for `contracts/access/Ownable.sol` are in `test/access/Ownable.test.js` + +### Testing Conventions + +When writing tests, follow these conventions: + +1. **Descriptive Names**: Test descriptions should clearly state what is being tested. + ```javascript + it('reverts when transferring tokens to the zero address', async function () { ... }); + ``` + +2. **Isolation**: Each test should be independent and not rely on the state of other tests. + +3. **Complete Coverage**: Aim for 100% code coverage, testing both the normal execution paths and edge cases. + +4. **Testing Modifiers**: When testing modifiers, ensure that both success and failure cases are tested. + +5. **Event Testing**: Verify that events are emitted with the correct parameters. + +6. **Gas Efficiency**: Consider using the gas reporter to monitor the gas costs of functions. + +### Fixtures and Utilities + +The `test/helpers` directory contains reusable testing utilities, including: + +- Fixtures for common test setups +- Helper functions for frequently used test operations +- Custom matchers for common assertions + +### Best Practices + +1. **Test State Changes**: Verify that state variables are modified correctly. + +2. **Test Reverts**: Use `expectRevert` to test functions that should revert in specific circumstances. + ```javascript + await expectRevert( + token.transfer(constants.ZERO_ADDRESS, 100), + 'ERC20: transfer to the zero address' + ); + ``` + +3. **Test Access Control**: Ensure that functions properly restrict access when required. + +4. **Test Upgrade Paths**: For upgradeable contracts, test that the upgrade path works correctly. + +### Continuous Integration + +All tests run on GitHub Actions for each pull request. PRs will not be merged if tests fail. + +### Coverage + +Test coverage is tracked using [solidity-coverage](https://github.com/sc-forks/solidity-coverage). Run the following command to generate a coverage report: + +```bash +npm run coverage +``` + +### Contributing Tests + +When contributing new features or fixing bugs: + +1. Always add tests that cover the changes +2. Make sure all existing tests pass +3. Consider edge cases and error conditions +4. Update test documentation if necessary + +### Snapshot Testing + +For complex data structures or large state changes, consider using snapshot testing to compare expected and actual values. + +### Security-Specific Testing + +For security-critical functions, consider adding specialized tests: + +1. **Fuzzing**: Use tools like Echidna or Foundry to fuzz test inputs +2. **Invariant Testing**: Identify and test invariants that should always hold +3. **Scenario Testing**: Test full user interaction flows + +### Resources + +For more information on testing smart contracts, refer to: +- [Hardhat Documentation](https://hardhat.org/getting-started/) +- [OpenZeppelin Test Helpers](https://docs.openzeppelin.com/test-helpers) +- [Effective Smart Contract Testing](https://blog.openzeppelin.com/effective-smart-contract-testing/)