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

Я хочу проверить следующую логику (это, очевидно, урезанная версия моего метода):

public void myPublicMethod(params) {

    if(some_condition)
        privateMethod1();
    else
        privateMethod2();
} 

У меня отключены все другие зависимости в методе, и я настроил это так, чтобы я мог гарантировать, что some_condition имеет значение true. Я хочу убедиться, что мой privateMethod1() вызывается ровно один раз, а privateMethod2() вообще не вызывается. Это возможно сделать с Moq?

Вот несколько заметок по этому вопросу:

  • privateMethod1() и privateMethod2() находятся в одном классе с myPublicMethod, поэтому я не могу создать фиктивный объект для этого класса.
  • Тела privateMethod1/2 содержат много, много зависимостей от класса, который содержит их и myPublicMethod, поэтому разбиение privateMethod1/2 на их собственный вспомогательный класс будет непомерно трудоемким

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

2 ответа

Решение

Не проверяйте частные методы. Они являются частными деталями реализации класса. Вам следует только проверить результаты выполнения открытых методов. Пока ваши результаты получаются, как и ожидалось, вам все равно, как результат получен.

Создание тестов для частных методов приведет к хрупким тестам, которые легко ломаются при рефакторинге частных реализаций (по причинам производительности или по другим причинам).

В вашем классе есть два закрытых служебных метода, которые инкапсулируют некоторое полезное поведение, и открытый метод, который вы тестируете, должен использовать это поведение. Однако, когда вы тестируете, вы не хотите нормального поведения от этих методов, вы хотите заменить тестовое поведение. То, что у вас есть, это классический случай зависимости. При тестировании зависимости внутри класса могут быть проблематичными.

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

private Action Behavior1;
private Action Behavior2;

В конструкторе класса нормальное поведение реализовано так:

public Foo (...)
{
    Behavior1 = privateMethod1;
    Behavior2 = privateMethod2;
...
}

В публичном методе делегат вызывается вместо фактического метода:

public void myPublicMethod(params) {
    if(some_condition)
        Behavior1();
    else
        Behavior2();
} 

Таким образом, абсолютная зависимость между методами была устранена, поэтому теперь она может быть проверена.

Итак, теперь в тесте после создания экземпляра тестового объекта вы можете переопределить зависимое поведение:

Foo_Accessor testMe = new Foo_Accessor();

bool wasCalled1 = false

testMe.Behavior1 = new Action(() => wasCalled1 = true);

...

Assert.IsTrue(wasCalled1);
Другие вопросы по тегам