在同一模拟实例上断言对公共方法的调用
本文关键字:方法 调用 断言 模拟 实例 | 更新日期: 2023-09-27 18:05:24
我有以下测试
[Test]
public void Attack_TargetWith3Damage_CausesAttackerToDeal3DamageToTarget()
{
var realAttacker = CreateCreature(damage: 3);
var wrappedAttacker = A.Fake<ICreature>(x => x.Wrapping(realAttacker));
var target = A.Fake<ICreature>();
wrappedAttacker.Attack(target);
A.CallTo(() => wrappedAttacker.DealDamage(target, 3)).MustHaveHappened();
}
问题是Attack
方法对DealDamage
的调用没有被注册,因为在方法内部,this
是realAttacker
而不是wrappedAttacker
攻击者,因此方法调用没有被拦截。
如何测试这个断言?FakeItEasy能做到这一点吗?是否有不同的mock框架允许我对此进行测试?
在使用Moq作为mock框架后,您可以获得非常接近的效果。
以以下为例:
public interface ICreature { ... }
public class Creature : ICreature
{
...
public void Attack(ICreature creature)
{
DealDamage(creature, 3); // Hard-coded 3 to simplify example only
}
public virtual void DealDamage(ICreature target, int damage) { ... }
}
.... Test ....
var wrappedAttacker = new Mock<Creature>();
var mockTarget = new Mock<ICreature>();
wrappedAttacker.Object.Attack(mockTarget.Object);
wrappedAttacker.Verify(x => x.DealDamage(mockTarget.Object, 3), Times.Once());
在本例中,我将Creature
实例"包装"在攻击者角色的模拟中,并为目标角色创建ICreature
模拟。然后我从攻击者那里调用Attack
方法;验证同一个攻击者的DealDamage
被调用(正确的目标和3点伤害),正好是一次。
在Moq中使此验证成为可能的原因是DealDamage
函数被标记为virtual
。对于您的情况,这可能是一个交易破坏者,但它确实解决了"不同的mock框架允许我测试这个吗?""问题。
感谢@ckittel为我指出这个答案。要做到这一点,Creature
类需要有一个无参数的构造函数,并且方法需要是虚的。
FakeItEasy的一个额外的事情似乎是你必须告诉它调用基方法,否则在概念上它是相同的,只是语法不同。
[Test]
public void Attack_TargetWith3Damage_CausesAttackerToDeal3DamageToTarget()
{
var attacker = A.Fake<Creature>();
A.CallTo(attacker).CallsBaseMethod(); //Otherwise it seems all calls are no-ops.
attacker.Stats.Damage = 3;
var target = A.Fake<ICreature>();
attacker.Attack(target);
A.CallTo(() => attacker.DealDamage(target, 3)).MustHaveHappened();
}