Mam następujący test

[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();
}

Problem polega na tym, że wywołanie DealDamage z metody Attack nie jest rejestrowane, ponieważ wewnątrz metody this jest realAttacker nie wrappedAttacker atakującym, a zatem wywołanie metody nie jest przechwytywane.

Jak mogę przetestować to twierdzenie? Czy można to zrobić za pomocą FakeItEasy? Czy inny framework do prześmiewania pozwala mi to przetestować?

5
Davy8 14 sierpień 2011, 08:12
To jest problem, którego doświadczyłem również z NSubstitute.
 – 
IAbstract
14 sierpień 2011, 08:29

2 odpowiedzi

Najlepsza odpowiedź

Dzięki @ckittel za wskazanie mi tej odpowiedzi. Aby to zadziałało, klasa Creature musi mieć konstruktor bez parametrów, a metody muszą być wirtualne.

Jedna dodatkowa rzecz z FakeItEasy wydaje się, że musisz powiedzieć mu, aby wywołała metodę podstawową, w przeciwnym razie koncepcyjnie jest to ta sama, tylko inna składnia.

[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();
}
1
ckittel 15 sierpień 2011, 04:31
FWIW, jeśli chodzi o parametry konstruktora, moq nie ma tego ograniczenia. W razie potrzeby mogłem podać argumenty konstruktora, po prostu nie zrobiłem tego w mojej odpowiedzi, aby było to proste.
 – 
ckittel
15 sierpień 2011, 03:43

Po użyciu Moq do swojego frameworka do fałszowania możesz zbliżyć się do tego, co już jesteś.

Weź to jako przykład:

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());

W tym przypadku „pakuję” Creature instancję w makietę roli atakującego i tworzę makietę ICreature dla roli docelowej. Następnie wywołuję metodę Attack od atakującego; sprawdzenie, czy DealDamage tego samego atakującego zostało wywołane (z prawidłowym celem i 3 obrażeniami), dokładnie jeden raz.

To, co umożliwia tę weryfikację w Moq, to ​​fakt, że funkcja DealDamage jest oznaczona virtual. To może być przełomem w Twojej sytuacji, ale odpowiada na pytanie „Czy inne ramy szyderstwa pozwalają mi to przetestować?”.

3
ckittel 14 sierpień 2011, 19:29
Więc ... OP musi sprawdzić, czy jest coś takiego jak CallBase w FakeItEasy. Muszę sprawdzić z NSub i zobaczyć, czy istnieje podobna metoda. Spodziewam się, że większość frameworków do prześmiewania byłaby nieco podobna.
 – 
IAbstract
14 sierpień 2011, 19:26
W rzeczywistości właśnie odkryłem, że CallBase nie jest nawet potrzebne w tej sytuacji, uporządkowałem swoją odpowiedź jako taką.
 – 
ckittel
14 sierpień 2011, 19:30