Używanie Moq do określenia, czy wywoływana jest metoda

159

Rozumiem, że mogę sprawdzić, czy wywołanie metody nastąpi, jeśli wywołam metodę wyższego poziomu, tj .:

public abstract class SomeClass()
{    
    public void SomeMehod()
    {
        SomeOtherMethod();
    }

    internal abstract void SomeOtherMethod();
}

Chcę sprawdzić, czy jeśli zadzwonię SomeMethod(), spodziewam się, że SomeOtherMethod()zostanie wezwany.

Czy mam rację, myśląc, że ten rodzaj testu jest dostępny w fałszywej strukturze?

piekarnik
źródło

Odpowiedzi:

186

Możesz sprawdzić, czy metoda w czymś, co wyszydziłeś, została wywołana za pomocą funkcji Verify, np .:

static void Main(string[] args)
{
        Mock<ITest> mock = new Mock<ITest>();

        ClassBeingTested testedClass = new ClassBeingTested();
        testedClass.WorkMethod(mock.Object);

        mock.Verify(m => m.MethodToCheckIfCalled());
}

class ClassBeingTested
{
    public void WorkMethod(ITest test)
    {
        //test.MethodToCheckIfCalled();
    }
}

public interface ITest
{
    void MethodToCheckIfCalled();
}

Jeśli wiersz zostanie skomentowany, zgłosi MockException po wywołaniu Verify. Jeśli nie zostanie skomentowany, przejdzie.

Paweł
źródło
7
To jest poprawna odpowiedź. Musisz jednak coś zrozumieć. NIE MOŻESZ mockować metody / właściwości, która nie jest abstrakcyjna ani wirtualna (oczywiście wszystkie metody i właściwości interfejsu mogą być mockowane).
25
-1: .Expect (...). Verifiable () jest redundantne w tym kodzie. Używając AAA weryfikacja, którą masz, jest właściwa. .Verifiable jest do użytku z .Verify () i, .e. wersja bez arg. Zobacz stackoverflow.com/questions/980554/…
Ruben Bartelink
@ I - tak, to może
reggaeguitar
6

Nie, testy próbne zakładają, że używasz pewnych testowalnych wzorców projektowych, z których jeden to wstrzykiwanie. W twoim przypadku będziesz testować SomeClass.SomeMethod i SomeOtherMethodmusisz zostać zaimplementowany w innej jednostce, która wymaga interfejsu.

Twój Someclasskonstruktor by wyglądał New(ISomeOtherClass). Następnie kpiłbyś z niego ISomeOtherClassi oczekiwał, SomeOtherMethodże zostanie wywołany, i zweryfikuj to oczekiwanie.

Val
źródło
0

Mimo że zgadzam się, że odpowiedź @ Paul jest zalecaną drogą, chcę tylko dodać jedną alternatywną drogę, która jest zapewniana przez „ moqpoza sobą”.

Ponieważ SomeClassjest abstractrzeczywiście kpiny, ale public void SomeMehod()nie jest. Chodzi o to, aby znaleźć sposób na mock i jakoś wywołać tę metodę, a następnie za pomocą CallBasepropagacji wywołania do SomeOtherMethod(). Może to zabrzmieć jak włamanie, ale w istocie jest proste. Można by to wykorzystać w przypadku, gdy proponowana refaktoryzacja nie jest możliwa.

// This class is used only for test and purpose is make SomeMethod mockable
public abstract class DummyClass : SomeClass
{
    public virtual void DummyMethod() => base.SomeMethod();
}

Następnie można skonfigurować DummyMethod()propagowanie wywołania przez ustawienie CallBaseflagi.

//Arrange
var mock = new Mock<DummyClass>();
mock.Setup(m => m.DummyMethod()).CallBase();

//Act
mock.Object.SomeMethod();

//Assert
mock.Verify(m => m.SomeOtherMethod(), Times.Once);
Jasio
źródło
Ocena negatywna, ponieważ jest bardziej skomplikowana i wymaga standardowego DummyClass
reggaeguitar
przegłosowano, ponieważ czasami nie można refaktoryzować i trzeba przetestować implementację w obecnym stanie
wickdninja