Usando o Moq para determinar se um método é chamado

159

Entendo que posso testar se uma chamada de método ocorrerá se eu chamar um método de nível superior, ou seja:

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

    internal abstract void SomeOtherMethod();
}

Quero testar se, se eu ligar SomeMethod(), espero que SomeOtherMethod()isso seja chamado.

Estou certo ao pensar que esse tipo de teste está disponível em uma estrutura de simulação?

Owen
fonte

Respostas:

186

Você pode ver se um método em algo que você zombou foi chamado usando o Verify, por exemplo:

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 a linha for deixada comentada, lançará uma MockException quando você chamar Verify. Se não estiver comentado, passará.

Paulo
fonte
7
Essa é a resposta correta. Você deve entender alguma coisa, no entanto. Você NÃO PODE zombar de um método / propriedade que não seja abstrato ou virtual (obviamente, todos os métodos e propriedades da interface podem ser zombados).
25
-1: O .Expect (...). Verificável () é redundante neste código. Usando AAA, verifique se você está certo. .Verificiable é para uso com .Verify () i, .e. a versão sem argumento. Veja stackoverflow.com/questions/980554/…
Ruben Bartelink
@ Eu- sim pode
reggaeguitar
6

Não, o teste simulado pressupõe que você esteja usando determinados padrões de design testáveis, um dos quais é a injeção. No seu caso, você estaria testando SomeClass.SomeMethod e SomeOtherMethoddeve ser implementado em outra entidade que precisa ser conectada.

O seu Someclassconstrutor seria semelhante New(ISomeOtherClass). Em seguida, você zombaria ISomeOtherClasse definiria a expectativa SomeOtherMethodde ser chamado e verificaria a expectativa.

Val
fonte
0

Embora eu concorde que a resposta do @ Paul é o caminho recomendado, eu só quero adicionar um caminho alternativo que é fornecido por você moqmesmo.

Desde SomeClassé abstractque é realmente mockable, mas public void SomeMehod()não é. O objetivo é encontrar a maneira de zombar e de alguma forma invocar esse método e, em seguida, usar a CallBasepropagação da chamada para o SomeOtherMethod(). Pode parecer um hack, mas é simples em essência. Pode ser usado no caso se a refatoração proposta não for possível.

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

Em seguida, você pode configurar DummyMethod()para propagar a chamada definindo CallBasesinalizador.

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

//Act
mock.Object.SomeMethod();

//Assert
mock.Verify(m => m.SomeOtherMethod(), Times.Once);
Johnny
fonte
Downvoted porque é mais complicado e requer um clichê DummyClass
reggaeguitar
upvoted porque às vezes você não pode refatorar e você precisa testar a implementação, tal como está
wickdninja