2015-07-09 5 views
2

У меня есть открытый метод в классе, который внутренне вызывает частный частный метод внутри этого класса. Это выглядит примерно так:Протестировать общедоступный метод, который вызывает частный метод с использованием NUnit

public class MyClass : IMyClassInterface 
{ 
    public List<int> MyMethod(int a, int b) 
    { 
     MyPrivateMethod(a, b, ref varList, ref someVal); 
    } 
    private void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval) 
    { 
    } 
} 

Теперь я хочу протестировать этот публичный метод, используя NUnit. Я использую NMock 2.0 для насмешек. Как мне это сделать? Поскольку он внутренне вызывает этот частный метод, который я не хочу публиковать. Или есть способ сделать это, если вместо этого я вернусь к приватному методу?

+1

Закрытый метод представляет собой деталь реализации публичного метода. Вы должны тестировать его как часть тестирования общедоступного метода. Если метод ничего не сделал, вы бы все же считали, что ваши тесты общественного метода действительны? Если да, то почему вы это называете? – forsvarir

+0

Я не был уверен. Если вообще мы должны проверить частный метод как часть общедоступного метода или нет. Имеет смысл протестировать его как часть общедоступного метода. – Siddhant

+0

Тем не менее, если бы я просто хотел проверить, вызван ли этот частный метод или нет, то защита его будет, безусловно, помогать. – Siddhant

ответ

3

Да, «трюк» должен использовать защищенный вместо частного, а затем наследовать класс и запускать тест нового класса, который выполняет защищенный метод. Это очень распространенный способ проверки кода и старого кода.

[TestClass] 
    public class UnitTest1 
    { 
     [TestMethod] 
     public void TestMethod1() 
     { 
      MyClassTestWrapped t = new MyClassTestWrapped(); 
      Assert.IsTrue(t.MyPrivateMethod(...)); 
      Assert.IsTrue(t.MyMethod(...)); 

      MockFactory _factory = new MockFactory(); 
      Mock<MyClassTestWrapped> mock; 

      mock = _factory.CreateMock<MyClass>(); 
      mock.Expects.One.MethodWith(d => d.MyPrivateMethod()); // do the nmock magic here 


     } 
    } 

    public class MyClass : IMyClassInterface 
    { 
     public List<int> MyMethod(int a, int b) 
     { 
      MyPrivateMethod(a, b, ref varList, ref someVal); 
     } 
// here change to protected 
     protected void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval) 
     { 
     } 
    } 

    public interface IMyClassInterface 
    { 

    } 

    public class MyClassTestWrapped : MyClass 
    { 
     public List<int> MyMethod(int a, int b) 
     { 
      base.MyMethod(a, b); 
     } 

     public List<int> MyPrivateMethod(int a, int b,ref List<int> varList, ref double someval) 
     { 
      base.MyPrivateMethod(a, b, ref varList, ref someval); 
     } 

    } 
+0

Спасибо. Это должно помочь. Хотя вы могли бы рассказать мне, как я издеваюсь над защищенным методом с использованием NMock, когда я тестирую свой общедоступный метод. Общественный метод вызывает это из своего определения. Или вы можете направить меня на сайт, который мог бы предоставить мне информацию об этом же. – Siddhant

+0

Насколько я знаю, вы должны издеваться над тестируемым классом, используя NMock (Mock Thorarins

+0

Спасибо. Я попробую. – Siddhant

4

Теперь я в основном хотят, чтобы проверить это публичный метод (...)

Это здорово. Это то, что вы должны делать. Забудьте о внутренних деталях на мгновение. С точки зрения общественного метода, есть ли разница между этими двумя фрагментами?

// Your current implementation 
public void MyMethod(int a, int b) 
{ 
    MyPrivateMethod(a, b); 
} 
private void MyPrivateMethod(int a, int b) 
{ 
    var c = a + b; 
    // some more code 
} 

// Private method inlined 
public void MyMethod(int a, int b) 
{ 
    var c = a + b; 
    // some more code 
} 

Кто называет (общественные) MyMethod не будет в состоянии заметить разницу между этими двумя. Конечный результат тот же. Не имеет значения, есть ли вызов частного метода, потому что, насколько это касается публичного API, это не имеет значения. Вы можете встроить частный метод, заставить его уйти навсегда, а с точки зрения общественного потребителя ничего не меняется. Конечный результат - это единственное, что важно. Вы конечный результат теста можно наблюдать по коду потребителя. Не какая-то внутренняя тарабарщина.

Важная реализация заключается в следующем:

Правильно спроектированные SOLID код никогда не поставит вас в положение, которое потребует от вас сделать личное насмешки. Источник проблемы? Плохой дизайн.

Источник: How to mock private method - solutions

Угу. Грустно, но верно, ваш дизайн не так уж и хорош. В зависимости от того, хотите ли вы изменить это или нет, есть несколько подходов можно принять:

  • не пытаются издеваться частные детали, сосредоточиться на общественном API (не помогает проблемы дизайна)
  • извлекать частный метод в класс, вводить зависимость (долгосрочное решение, улучшает дизайн и делает код легко проверяемым)
  • защищать частный метод, переопределять в тесте, как предложено в другом ответе (не помогает при разработке проблемы, может не дать ценный тест)

Какой бы вы ни выбрали, я lea до вас. Тем не менее, я еще раз подчеркнуть это - mocking private method не является проблемой модульного тестирования, библиотеки или инструментов - это проблема с дизайном и лучше всего разрешима как таковая.


На боковой ноте (если вы можете) не использовать NMock2. Это библиотека с последними изменениями с 2009 года. Это похоже на наличие 30-летнего автомобиля, который последний раз обслуживался 15 лет назад. В настоящее время есть намного лучшие (FakeItEasy, Moq, NSubstitute).

1

В настоящее время вы должны реорганизовать свой код, чтобы освободить частный модификатор (обертки, а что нет). Вы можете сделать это довольно легко с помощью инструментов типа Typemock Isolator.

Я добавил код на свой пример, чтобы написать тест:

public class MyClass 
{ 
    public List<int> MyMethod(int a, int b) 
    { 
     List<int> varList = new List<int>(); 
     double someVal = 0; 

     MyPrivateMethod(a, b, ref varList, ref someVal); 

     return varList; 
    } 

    private void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval) 
    { 
    } 
} 

С этим прямым вперед подходом вы просто подделать частный метод, как это в коде (никаких изменений в производстве), даже не пришли ref:

[Test] 
public void TestMethod1() 
{ 
    //Arrange 
    var myClass = new MyClass(); 
    var expectedVarList = new List<int> {1,2,3}; 

    Isolate.NonPublic.WhenCalled(myClass, "MyPrivateMethod") 
     .AssignRefOut(expectedVarList, 0.0) 
     .IgnoreCall(); 

    //Act 
    var resultVarList = myClass.MyMethod(0, 0); 

    //Assert 
    CollectionAssert.AreEqual(expectedVarList, resultVarList); 

} 
Смежные вопросы