在单元测试中使用 Waffle 模拟合约作为方法的调用者
Use a Waffle mock contract as a callee of a method in a unit test
问题:我想测试一个方法只能被另一个合约调用。
示例:
// B.sol
contract B {
A _a;
uint256 i;
constructor(A a) {
_a = a;
i = 0;
}
function doSomething() external {
require(address(_a) == msg.sender);
i += 1;
}
}
// A.sol
contract A {
B _b;
constructor(B b) {
_b = b;
}
function callB() external {
_b.doSomething();
}
}
// B.test.ts
// going to simplify some unimportant stuff here
describe('doSomething', () => {
it('should fulfil when called by contract A', async () => {
const mockA = await deployMockContract('A'); // Waffle
const b = await bFactory.deploy();
const signerFromMockA = b.provider.getSigner(mockA.address);
const bAsMockA = b.connect(signerFromMockA);
await expect(bAsMockA.doSomething()).to.have.eventually.fulfilled;
})
it('should reject when called by other address', async () => {
const mockA = await deployMockContract('A'); // Waffle
const b = await bFactory.deploy();
const [, nonOwner] = ethers.getSigners();
const bAsNonOwner = b.connect(nonOwner);
await expect(bAsNonOwner.doSomething()).to.have.eventually.rejected;
})
})
我希望这能通过,但我收到“未知帐户”AssertionError,表明联系方法只能由以太生成的签名者调用。
(请忽略构造函数之间的循环依赖。这不是本例的重点。)
您可以使用 impersonating an account in hardhat.
基本上,智能合约地址无法像任何其他 EOA 那样自行签署交易,换句话说,它们无法使用 eth_sendTransaction
.
幸运的是,Hardhat 让您可以模拟帐户(this 回答很好地解释了模拟的概念)。
按照您的示例,要模拟 mockA
合约,您需要执行以下操作:
// more imports...
import { ethers, network } from 'hardhat';
describe('doSomething', () => {
it('should fulfil when called by contract A', async () => {
const mockA = await deployMockContract('A'); // Waffle
// impersonate mockA address
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [mockA.address],
});
// get MockA signer as an impersonated account
// that is able to sign txs using `eth_sendTransaction`
const mockAAsSigner = ethers.getSigner(mockA.address);
const b = await bFactory.deploy();
// connect you contract with mockAAsSigner;
const bAsMockA = b.connect(mockAAsSigner);
// Call bAsMockA contract acting as mockAAsSigner
await expect(bAsMockA.doSomething()).to.have.eventually.fulfilled;
})
});
当然,模拟账户只能在 Hardhat 网络中使用。
问题:我想测试一个方法只能被另一个合约调用。
示例:
// B.sol
contract B {
A _a;
uint256 i;
constructor(A a) {
_a = a;
i = 0;
}
function doSomething() external {
require(address(_a) == msg.sender);
i += 1;
}
}
// A.sol
contract A {
B _b;
constructor(B b) {
_b = b;
}
function callB() external {
_b.doSomething();
}
}
// B.test.ts
// going to simplify some unimportant stuff here
describe('doSomething', () => {
it('should fulfil when called by contract A', async () => {
const mockA = await deployMockContract('A'); // Waffle
const b = await bFactory.deploy();
const signerFromMockA = b.provider.getSigner(mockA.address);
const bAsMockA = b.connect(signerFromMockA);
await expect(bAsMockA.doSomething()).to.have.eventually.fulfilled;
})
it('should reject when called by other address', async () => {
const mockA = await deployMockContract('A'); // Waffle
const b = await bFactory.deploy();
const [, nonOwner] = ethers.getSigners();
const bAsNonOwner = b.connect(nonOwner);
await expect(bAsNonOwner.doSomething()).to.have.eventually.rejected;
})
})
我希望这能通过,但我收到“未知帐户”AssertionError,表明联系方法只能由以太生成的签名者调用。
(请忽略构造函数之间的循环依赖。这不是本例的重点。)
您可以使用 impersonating an account in hardhat.
基本上,智能合约地址无法像任何其他 EOA 那样自行签署交易,换句话说,它们无法使用 eth_sendTransaction
.
幸运的是,Hardhat 让您可以模拟帐户(this 回答很好地解释了模拟的概念)。
按照您的示例,要模拟 mockA
合约,您需要执行以下操作:
// more imports...
import { ethers, network } from 'hardhat';
describe('doSomething', () => {
it('should fulfil when called by contract A', async () => {
const mockA = await deployMockContract('A'); // Waffle
// impersonate mockA address
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [mockA.address],
});
// get MockA signer as an impersonated account
// that is able to sign txs using `eth_sendTransaction`
const mockAAsSigner = ethers.getSigner(mockA.address);
const b = await bFactory.deploy();
// connect you contract with mockAAsSigner;
const bAsMockA = b.connect(mockAAsSigner);
// Call bAsMockA contract acting as mockAAsSigner
await expect(bAsMockA.doSomething()).to.have.eventually.fulfilled;
})
});
当然,模拟账户只能在 Hardhat 网络中使用。