Использование Moq для определения, вызывается ли метод

159

Насколько я понимаю, я могу проверить, что вызов метода произойдет, если я вызову метод более высокого уровня, то есть:

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

    internal abstract void SomeOtherMethod();
}

Я хочу проверить, что если я позвоню, SomeMethod()то я ожидаю, что SomeOtherMethod()это будет называться.

Правильно ли я считаю, что такого рода тесты доступны для насмешки?

Оуэн
источник

Ответы:

186

Вы можете увидеть, был ли вызван метод в чем-то, что вы смоделировали, используя Verify, например:

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

Если строка оставлена ​​закомментированной, она вызовет исключение MockException при вызове Verify. Если он не прокомментирован, он пройдет.

Павел
источник
7
Это правильный ответ. Вы должны что-то понять, однако. Вы НЕ МОЖЕТЕ насмехаться над методом / свойством, которое не является абстрактным или виртуальным (очевидно, все методы и свойства интерфейса могут быть смоделированы).
25
-1: .Expect (...). Verifiable () избыточна в этом коде. Используя AAA, убедитесь, что у вас есть право. .Verifiable предназначен для использования с .Verify () i, .e. версия без аргументов. См stackoverflow.com/questions/980554/...
Ruben Bartelink
@ Я - да, это возможно
регги-гитара,
6

Нет, фиктивное тестирование предполагает, что вы используете определенные тестируемые шаблоны проектирования, одним из которых является внедрение. В вашем случае вы будете тестировать SomeClass.SomeMethod и SomeOtherMethodдолжны быть реализованы в другом объекте, который должен быть сопряжен.

Ваш Someclassконструктор будет выглядеть так New(ISomeOtherClass). Затем вы высмеиваете ISomeOtherClassи устанавливаете ожидание SomeOtherMethodвызова и проверяете ожидание.

Val
источник
0

Несмотря на то, что я согласен с тем, что ответ @ Paul - рекомендуемый путь, я просто хочу добавить один альтернативный путь, который обеспечивается самим moqсобой.

Так SomeClassкак abstractэто действительно издевательство, но public void SomeMehod()это не так. Суть в том, чтобы найти способ смоделировать и каким-то образом вызвать этот метод, а затем с помощью CallBaseраспространения передать вызов SomeOtherMethod(). Это может звучать как взломать, но это просто по сути. Это может быть использовано в том случае, если предложенный рефакторинг невозможен.

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

Затем вы можете настроить DummyMethod()передачу вызова, установив CallBaseфлажок.

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

//Act
mock.Object.SomeMethod();

//Assert
mock.Verify(m => m.SomeOtherMethod(), Times.Once);
Джонни
источник
Понижено, потому что это более сложный и требует шаблон DummyClass
reggaeguitar
проголосовал, потому что иногда вы не можете рефакторинг, и вам нужно проверить реализацию в ее нынешнем виде
wickdninja