Вызов метода C # Moq Intercept - PullRequest
0 голосов
/ 26 апреля 2018

Я не уверен, что то, что я хочу сделать, возможно. У меня есть интерфейс, который выглядит так:

public interface IObject
{
     void MethodA(ObjectA arg1);
     void MethodB(ObjectB arg1, ObjectC arg2);
     void MethodC(ObjectD arg1, ObjectE arg2);
}

У меня есть что-то вроде следующей реализации:

public class ObjectImplementation : IObject
{
     public void MethodA(ObjectA arg1)
     {
          if(arg1.Something)
          {
               MethodB(new ObjectB(arg1), new ObjectC(arg1));
          }
          else
          {
               MethodC(new ObjectD(arg1), new ObjectE(arg1));
          }
     }
}

Я пытаюсь написать модульный тест, чтобы проверить, выполняются ли эти вызовы methodB или methodC в соответствии с моим состоянием. Как чего-то подобного можно достичь?

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

Вы пытаетесь смоделировать интерфейс и проверить реализацию этого интерфейса.

Вы можете сделать методы C и D виртуальными и использовать реализацию в макете.

Реализация:

public class ObjectImplementation : IObject
{
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            MethodB(new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            MethodC(new ObjectD(arg1), new ObjectE(arg1));
        }
    }

    public virtual void MethodB(ObjectB arg1, ObjectC arg2)
    {

    }

    public virtual void MethodC(ObjectD arg1, ObjectE arg2)
    {

    }
}

Тест:

[Fact]
public void Test_WhenSomethingIsTrue_MethodB_Invoked_WithObjects_B_And_C()
{
    // Arrange
    Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
    ObjectA arg = new ObjectA();
    arg.Something = true;

    // Act
    mockObject.Object.MethodA(arg);

    // Assert
    mockObject.Verify(o => o.MethodB(It.Is<ObjectB>(b=> b.Arg == arg), It.Is<ObjectC>(c => c.Arg == arg)));
}

[Fact]
public void Test_WhenSomethingIsFalse_MethodC_Invoked_WithObjects_D_And_E()
{
    // Arrange
    Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
    ObjectA arg = new ObjectA();
    arg.Something = false;

    // Act
    mockObject.Object.MethodA(arg);

    // Assert
    mockObject.Verify(o => o.MethodC(It.Is<ObjectD>(d => d.Arg == arg), It.Is<ObjectE>(e => e.Arg == arg)));
}
0 голосов
/ 26 апреля 2018

Хотя принятое решение должно работать, я настоятельно рекомендую вам не проводить такого рода тесты. Каждый вызов метода приводит к некоторому выводу и некоторым побочным эффектам. Итак, если нет вывода и нет побочных эффектов, то метод просто ничего не делает. Утверждая, какой MethodB или MethodC был вызван, вы не проверяете выходные данные MethodA и их побочные эффекты. Такие тесты являются хрупкими, поскольку они тестируют только одну возможную реализацию метода A, а не то, что на самом деле делает . Под хрупким я подразумеваю следующее:

предположим, у вас есть следующая реализация IObject

class ObjectImpl
{
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            MethodB(new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            MethodC(new ObjectD(arg1), new ObjectE(arg1));
        }
    }

    public void MethodB(ObjectB arg1, ObjectC arg2)
    {
        Console.WriteLine("Hi {0} and {1}", arg1, arg2);
    }

    public void MethodC(ObjectD arg1, ObjectE arg2)
    {
        Console.WriteLine("Bye {0} and {1}", arg1, arg2);
    }
}

Итак, по сути, MethodA просто выводит «Hi» или «Bye» на консоль. Тогда, если кто-то заметит, что MethodB и MethodC не будут использоваться нигде, кроме MethodA, он может просто удалить их. Обратите внимание, что MethodA все тот же, поэтому ничего не сломалось, кроме теста.

class ObjectImpl
{
    // Everything works as before except broken build
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            Console.WriteLine("Hi {0} and {1}", new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            Console.WriteLine("Bye {0} and {1}", new ObjectD(arg1), new ObjectE(arg1));
        }
    }
}
0 голосов
/ 26 апреля 2018

Ну, почему вы не можете просто подделать этот метод-заглушку, как

Mock<IObject> m = new Mock<IObject>();
m.Setup(x => s.MethodB(new ObjectB(arg1), new ObjectC(arg1)))
 .Callback(() => Console.WriteLine("MethodB Called"));

Таким образом, если ваше условие if(arg1.Something) удовлетворяет, тогда будет вызван поддельный, и вы узнаете

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...