Рассмотрим следующий модульный тест Truffle, написанный на JavaScript:
const Lease = artifacts.require("./Lease.sol");
contract("Lease", async (accounts) => {
it("Rinkeby delay problem", async () => {
let instance = await Lease.deployed();
// let's check the initial state
let state0 = await instance.tenantState();
console.log("initial state: " + state0);
// let's change the state
let tx = {from:accounts[2], to:instance.address, value:2000};
web3.eth.sendTransaction(tx);
await instance.updateTenantState();
// let's check if the state changed
let state1 = await instance.tenantState();
console.log("resulting state: " + state1);
// let's wait for one second and check the state again
setTimeout(async () => {
await instance.updateTenantState();
let state2 = await instance.tenantState();
console.log("resulting state after 1 second: " + state2);
}, 1000);
});
});
Когда я запускаю этот тест на моем экземпляре GanacheUI с нулевыми задержками блоков, я получаю следующие результаты:
$ truffle test test/delay.test.js --network dev
Using network 'dev'.
Compiling ./contracts/Lease.sol...
Compiling ./contracts/LeaseMock.sol...
Compiling ./contracts/Logic.sol...
Contract: Lease
initial state: 1
resulting state: 0
✓ Delay problem (196ms)
1 passing (226ms)
resulting state after 1 second: 0
Однако, когда я добавляю 15-секундную задержку блока в GanacheUI (примерно такая же задержка блока, что и в основной сети), я получаю следующее:
$ truffle test test/delay.test.js --network dev
Using network 'dev'.
Compiling ./contracts/Lease.sol...
Compiling ./contracts/LeaseMock.sol...
Compiling ./contracts/Logic.sol...
Contract: Lease
initial state: 1
resulting state: 1
✓ Delay problem (30212ms)
1 passing (30s)
resulting state after 1 second: 0
Это катастрофически сказывается на моих модульных тестах: около 70% из них терпят неудачу с самыми разными ошибками.
Я получил похожие результаты с репозиторием AragonOS с использованием GanacheUI: без задержки блоков все тесты проходят успешно, но с задержкой блока 15 секунд многие терпят неудачу. (У них есть возможность протестировать на Ropsten, Kovan и Rinkeby с помощью Infura, но я этого не пробовал).
Итак, каковы лучшие практики? Должен ли я вообще игнорировать задержки блоков? В таком случае, как я должен тестировать свои контракты в тестовых сетях? Или мне следует спроектировать свои тесты так, чтобы они правильно обрабатывали задержки блоков? Если да, то как? И наконец: есть ли последствия для безопасности игнорирования блочных задержек в модульных тестах?
Лучше, если вы спроектируете свои тесты так, чтобы они не зависели от задержки между блоками. В реальной сети блоки генерируются в среднем каждые 15 секунд, и они могут занимать более длинные или более короткие интервалы. Также в будущем среднее значение сети может быть снижено.
В вашем модульном тесте проблема заключается в том, что вы запрашиваете изменение состояния вашего контракта. Вы не можете быть уверены, когда остановить опрос, в частной тестовой сети должно быть достаточно ожидания 30 секунд, в малоиспользуемой сети, такой как rinkeby, возможно, будет достаточно пары минут, но в загруженной сети, такой как основная сеть, 10 минут может быть недостаточно.
Лучший подход здесь — сгенерировать событие с вашей транзакцией и заставить ваш тест ждать запуска этого события. Вы должны убедиться, что используемая цена газа позволит обрабатывать транзакции с небольшой задержкой в общедоступной сети.