我有以下测试
[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();
}
问题是,DealDamage
方法对Attack
的调用未被注册,因为在方法内this
realAttacker
不是wrappedAttacker
攻击者因此没有拦截方法调用。
我该如何测试这个断言?可以用FakeItEasy完成吗?是否有一个不同的模拟框架允许我测试它?
答案 0 :(得分:3)
使用Moq作为模拟框架后,你可以非常接近你的目标。
以此为例:
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
。对于你的情况,这可能是一个交易破坏者,但它确实解决了“是否有一个不同的模拟框架允许我测试这个?”的问题。
答案 1 :(得分:1)
感谢@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();
}