@0xdomrom @joshpwrk After looking at the codebase, I want to propose something that adds more clarity to testing structure (process) and hopefully help with review process here:
What I see mostly done in the test folder are some tests between unit test and integration tests:
- they are not unit tests because we actually code bunch of logic in the "mock contracts" that interact with it, instead of only "mocking the return"
- they are not integration tests because they're not real modules that we wish the test the whole flow
I'd personally call these "POC tests": where we write sloppy code to test our hypothesis about:
- if the interface make sense
- if the whole workflow make sense
- what would the actual integrating modules "look like" (for example, the OptionToken and QuoteWrapper)
These are very important tests and I think we will each write bunch of them while designing the system in a modular way.
Problem
However the problem with "only having these kind of tests" is that it is very hard to "setup" a scenario and test some basic logic and make sure we make no mistake in some trivial things. If we're aiming for full coverage, this is gonna post a lot of unnecessary work.
Take allowance tests for example: see we have such a complicated setup, even deploying Lending
in deployPRMSystem
while I just want to test if allowance is working correctly with positive value / negative value, and if someone can steal money without proper allowance. Also if we add more "mock contracts" in the future, we will have to update these tests as well. (and the gas benchmark is gonna be inaccurate too and at some point we will ignore all of them)
function setUp() public {
deployPRMSystem();
setPrices(1e18, 1500e18);
PortfolioRiskManager.Scenario[] memory scenarios = new PortfolioRiskManager.Scenario[](1);
scenarios[0] = PortfolioRiskManager.Scenario({spotShock: uint(85e16), ivShock: 10e18});
setScenarios(scenarios);
aliceAcc = createAccountAndDepositUSDC(alice, 10000000e18);
bobAcc = createAccountAndDepositUSDC(bob, 10000000e18);
}
Proposal
I think we should have a separate folder of unit tests which should be very very simple to tests all the if-else branch, and make sure the function work as intended.
Take allowance for example, we just need to deploy Accounts
, and a super easy Asset
that add money into the account system, and we check if another user can update the account balance without allowance.
Ideally the setup should be as easy as
function setUp() public {
usdc = new TestERC20("usdc", "USDC");
usdcAsset = new QuoteWrapper(IERC20(usdc), account);
account = new Account("Lyra Margin Accounts", "LyraMarginNFTs");
aliceAcc = createAccountAndDepositUSDC(alice, 10000000e18);
bobAcc = createAccountAndDepositUSDC(bob, 10000000e18);
}
Where I don't need to know about what are scenarios
or every contract inside deployPRMSystem
, nor do i need to test things with a "OptionAdaptor".
This will make sure we have a set of tests that only "describe the behavior" of a single contract, and doesn't have any dependencies on anything else. In the future we don't have to change every single unit tests when we have a new "POC for OptionToken".
This is also to make sure we can look at the "unit tests" and see what the function are supposed to work, without knowing how the rest of the system works. Ideally when we start writing functions, we use these some super fast unit tests that make sure all the math, storage updates and access logic are taken care of, as a way to prove of correctness to the reviewers, and we use "POC tests" to show people what the rest of the world should look like (extremely important when we're still having some moving pieces with the design).
I think by having the consensus about different kind of tests, we can dramatically reduce the burden on both the coder and the reviewer. As we start to take care of our own modules and work in pipeline, it would become more and more time consuming for us to review each others' code if we require the knowledge about all moving pieces to review 1 simple test.
Next step:
What I plan on doing is I can have a guideline setup (including naming and folder separation) so we have consensus about what kind of tests are more of a "POC tests" that we don't have to care too much about until it's mark as final, and which are unit tests that best describe whats being implemented in a certain PR. This is also gonna be helpful for auditors to come in and look at our code.
I can add the guide line and start separating some unit tests for Accounts
, hopefully code will speak more straightforward