Utilizzo di Moq per determinare se viene chiamato un metodo


159

Comprendo che posso verificare che si verifichi una chiamata di metodo se chiamo un metodo di livello superiore, ovvero:

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

    internal abstract void SomeOtherMethod();
}

Voglio provare che se chiamo SomeMethod()allora mi aspetto che SomeOtherMethod()verrà chiamato.

Ho ragione nel pensare che questo tipo di test sia disponibile in un quadro beffardo?

Risposte:


186

Puoi vedere se un metodo in qualcosa che hai deriso è stato chiamato usando Verifica, ad esempio:

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

Se la riga viene lasciata commentata, verrà generata una MockException quando si chiama Verifica. Se è senza commento passerà.


7
Questa è la risposta corretta Devi capire qualcosa, comunque. NON PUOI deridere un metodo / proprietà che non sia astratto o virtuale (ovviamente, tutti i metodi e le proprietà dell'interfaccia possono essere derisi).

25
-1: .Expect (...). Verifiable () è ridondante in questo codice. Utilizzando AAA la verifica che hai è giusta. .Verifiable è per l'uso con .Verify () i, .e. la versione no arg. Vedere stackoverflow.com/questions/980554/...
Ruben Bartelink

@I-- sì, può
reggaeguitar,

6

No, i test di simulazione presuppongono che si stiano utilizzando determinati modelli di progettazione verificabili, uno dei quali è l'iniezione. Nel tuo caso verrai testato SomeClass.SomeMethod e SomeOtherMethoddevi essere implementato in un'altra entità che deve essere interfacciata.

Il tuo Someclasscostruttore sarebbe simile New(ISomeOtherClass). Quindi deriderebbe ISomeOtherClasse impostare l'attesa sulla sua SomeOtherMethodchiamata e verificarne l'attesa.


0

Anche se sono d'accordo sul fatto che la risposta di @ Paul sia la strada da percorrere consigliata, voglio solo aggiungere una via alternativa che è fornita da moqsé.

Dal momento che SomeClassè abstractè davvero mockable, ma public void SomeMehod()non lo è. Il punto è trovare il modo di deridere e in qualche modo invocare quel metodo e quindi usare CallBasepropagare la chiamata a SomeOtherMethod(). Potrebbe sembrare un trucco ma è semplice in sostanza. Potrebbe essere utilizzato nel caso in cui il refactoring proposto non fosse possibile.

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

Quindi è possibile impostare DummyMethod()per propagare la chiamata impostando CallBaseflag.

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

//Act
mock.Object.SomeMethod();

//Assert
mock.Verify(m => m.SomeOtherMethod(), Times.Once);

Sottovalutato perché è più complicato e richiede un DummyClass a piastra
reggaeguitar

votato perché a volte non è possibile effettuare il refactoring ed è necessario testare l'implementazione così com'è
wickdninja,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.