Использование внедрения зависимостей (вариант 2 или 4), безусловно, является моим предпочтительным методом атаки на это.Это не только облегчает тестирование, но и помогает разделить проблемы и не допустить раздувания классов.
Я хочу пояснить, что неверно то, что статические методы сложно тестировать.Проблема со статическими методами возникает, когда они используются в другом методе.Это затрудняет проверку метода, вызывающего статический метод, так как статический метод не может быть смоделирован.Обычный пример этого с I / O.В вашем примере вы пишете текст в файл (WriteTextToFile).Что если что-то не получится во время этого метода?Так как метод является статическим и его нельзя смоделировать, вы не можете по требованию создавать случаи, такие как случаи сбоев.Если вы создаете интерфейс, то вы можете посмеяться над вызовом WriteTextToFile и заставить его имитировать ошибки.Да, у вас будет еще несколько интерфейсов и классов, но обычно вы можете логически сгруппировать похожие функции в один класс.
Без внедрения зависимостей: Это в значительной степени вариант 1, где ничего не высмеивается,Я не рассматриваю это как надежную стратегию, потому что она не позволяет вам тщательно протестировать.
public void WriteMyFile(){
try{
using (FileStream fStream = File.Create(@"C:\test.txt")){
string text = MyUtilities.GetFormattedText("hello world");
MyUtilities.WriteTextToFile(text, fStream);
}
}
catch(Exception e){
//How do you test the code in here?
}
}
с внедрением зависимости:
public void WriteMyFile(IFileRepository aRepository){
try{
using (FileStream fStream = aRepository.Create(@"C:\test.txt")){
string text = MyUtilities.GetFormattedText("hello world");
aRepository.WriteTextToFile(text, fStream);
}
}
catch(Exception e){
//You can now mock Create or WriteTextToFile and have it throw an exception to test this code.
}
}
НаС другой стороны, хотите ли вы, чтобы ваши тесты бизнес-логики не сработали, если файловая система / база данных не могут быть прочитаны / записаны?Если мы проверяем правильность математики при расчете зарплаты, мы не хотим, чтобы ошибки ввода-вывода приводили к провалу теста.
Без внедрения зависимости:
Это немного странный пример / метод, но я использую его только для иллюстрации своей точки.
public int GetNewSalary(int aRaiseAmount){
//Do you really want the test of this method to fail because the database couldn't be queried?
int oldSalary = DBUtilities.GetSalary();
return oldSalary + aRaiseAmount;
}
С впрыском зависимости:
public int GetNewSalary(IDBRepository aRepository,int aRaiseAmount){
//This call can now be mocked to always return something.
int oldSalary = aRepository.GetSalary();
return oldSalary + aRaiseAmount;
}
Повышенная скорость - дополнительный бонус насмешки.IO является дорогостоящим, и сокращение IO увеличит скорость ваших тестов.Отсутствие необходимости ждать транзакции базы данных или функции файловой системы улучшит производительность ваших тестов.
Я никогда не использовал TypeMock, поэтому не могу много говорить об этом.Впрочем, у меня такое же впечатление, как и у вас, что, если вам придется его использовать, возможно, придется провести рефакторинг.