В последнее время я много размышлял о том, как лучше всего "имитировать" статический метод, который вызывается из класса, который я пытаюсь протестировать. следующий код, например:
using (FileStream fStream = File.Create(@"C:\test.txt"))
{
string text = MyUtilities.GetFormattedText("hello world");
MyUtilities.WriteTextToFile(text, fStream);
}
Я понимаю, что это довольно плохой пример, но он имеет три вызова статических методов, которые все немного отличаются: Файл. Создать функцию доступа к файловой системе, и я не владею этой функцией. MyUtilities.GetFormattedText - это принадлежащая мне функция, которая не имеет состояния. Наконец, MyUtilities.WriteTextToFile - это функция, которой я владею, и она обращается к файловой системе.
В последнее время я размышлял, если бы это был унаследованный код, как бы я мог провести его рефакторинг, чтобы сделать его более пригодным для модульного тестирования. Я слышал несколько аргументов в пользу того, что статические функции не следует использовать, потому что их сложно проверить. Я не согласен с этой идеей, потому что статические функции полезны, и я не думаю, что от полезного инструмента следует отказываться только потому, что используемый тестовый фреймворк не может справиться с этим очень хорошо.
После долгих поисков и размышлений, Я пришел к выводу, что есть в основном 4 шаблона или практики , которые можно использовать, чтобы сделать функции, вызывающие статические функции, тестируемыми по модулю. К ним относятся следующие:
Я слышал довольно много дискуссий о первых трех практиках, но когда я размышлял о решениях этой проблемы, мне пришла в голову четвертая идея внедрения зависимостей функций . Это похоже на скрытие статической функции за интерфейсом, но без необходимости создавать интерфейс и класс-оболочку. Примером этого может быть следующее:
public class MyInstanceClass
{
private Action<string, FileStream> writeFunction = delegate { };
public MyInstanceClass(Action<string, FileStream> functionDependency)
{
writeFunction = functionDependency;
}
public void DoSomething2()
{
using (FileStream fStream = File.Create(@"C:\test.txt"))
{
string text = MyUtilities.GetFormattedText("hello world");
writeFunction(text, fStream);
}
}
}
Иногда создание интерфейса и класса-оболочки для вызова статической функции может быть обременительным и может засорять ваше решение множеством небольших классов, единственной целью которых является вызов статической функции. Я за то, чтобы писать код, который легко тестировать, но эта практика кажется обходным путем для плохой среды тестирования.
Когда я думал об этих различных решениях, я пришел к пониманию, что все 4 практики, упомянутые выше могут применяться в разных ситуациях. Вот что я думаю, это правильные варианты применения описанных выше методов :
Это мои мысли, но я бы очень признателен за некоторые отзывы по этому поводу. Как лучше всего проверить код, в котором вызывается внешняя статическая функция?