IMO, придумать способ проверить код, который вы пишете, не будет больше проблем, чем оно того стоит. Наличие хороших тестов облегчает работу новых функций, исправление ошибок и поддержку вашего приложения. Исходя из того, что вы описали, я думаю, вам нужно решить, какие тесты лучше использовать в вашем случае: модульные тесты или интеграционные тесты.
Если вы хотите написать настоящие модульные тесты, вам придется абстрагироваться от инструмента командной строки, чтобы вы могли писать тесты для объекта, который всегда будет возвращать одинаковые ожидаемые ответы для ваших запросов. Если вы создадите интерфейс для переноса вызовов в инструмент командной строки, то вы можете легко смоделировать ответы. Если вы используете этот подход, важно помнить, что вы тестируете то, что ваш сервис реагирует, как и ожидалось, на вывод инструмента командной строки. Вам придется подделать все возможные ответы, которые может выдать инструмент командной строки. Очевидно, что если вывод очень сложный, это может быть не вариант. Если вы думаете, что можете подделать ответы, взгляните на некоторые из насмешливых рамок (мне нравится Moq ). Они значительно облегчат работу.
Другой подход заключается в использовании интеграционных тестов. Эти тесты будут основаны на том, что ваша служба запускает инструмент командной строки и проверяет реальные ответы, которые возвращает ваша служба. Такое тестирование, скорее всего, потребует от вас возврата к исходному состоянию компьютера, на котором вы тестируете, в исходное состояние, при условии, что приложение командной строки действительно внесет изменения в этот компьютер. По моему опыту, эти тесты обычно работают медленнее и их сложнее поддерживать. Однако, если данные, возвращаемые из инструмента командной строки, слишком трудно подделать, тогда можно использовать интеграционные тесты.
Другой подход, и, вероятно, тот, который я выбрал бы, состоит в том, чтобы использовать немного обоих. Когда инструмент командной строки легко подделать, используйте модульные тесты. Если это не так, используйте интеграционные тесты. Для своих проектов я очень предпочитаю, когда я могу написать настоящие модульные тесты, которые не зависят от чего-то внешнего. К сожалению, поскольку мне приходится иметь дело с большим количеством старого кода, это не всегда возможно. Однако, даже когда это так, я всегда чувствую себя лучше, если смогу пройти интеграционный тест высокого уровня для всего этого, просто для небольшого дополнительного покрытия. Например, если я пишу веб-сайт, у меня может быть 100 модульных тестов, которые охватывают все мелочи, связанные с созданием веб-страницы, но если я могу, у меня будет 1 или 2 интеграционных теста, которые делают веб запросить и проверить текст на странице, просто ради здравомыслия. Наличие обоих типов тестов определенно дает мне более высокий уровень уверенности в том, что код будет работать так, как ожидается, когда он будет запущен.
Надеюсь, это поможет.
РЕДАКТИРОВАТЬ
Я думал об этом еще немного, и может быть относительно простой способ провести модульное тестирование вашего приложения. Чтобы подделать входные данные из инструмента командной строки, просто запустите инструмент командной строки для любого сценария, который вы пытаетесь протестировать. Сохраните выходные данные в виде текстового файла, а затем используйте этот текстовый файл в качестве входных данных для теста. Если вы используете интерфейс и внедрение зависимостей, ваш сервисный код будет одинаковым, независимо от того, запускаете ли вы тесты или само приложение. Например, скажем, мы тестируем метод, который выведет номер версии CLI:
public interface ICommandLineRunner
{
string RunCommand(string command);
}
public class CLIService
{
private readonly ICommandLineRunner _cliRunner;
public CLIService(ICommandLineRunner cliRunner)
{
_cliRunner = cliRunner;
}
public string GetVersionNumber()
{
string output = _cliRunner.RunCommand("-version");
//Parse output and store in result
return result;
}
}
[Test]
public void Test_Gets_Version_Number()
{
var mockCLI = new Mock<ICommandLineRunner>();
mockCLI.Setup(a => a.RunCommand(It.Is<string>(s => s == "-version"))
.Returns(File.ReadAllText("version-number-output.txt"));
var mySvc = new CLIService(mockCLI.Object);
var result = mySvc.GetVersionNumber();
Assert.AreEqual("1.0", result);
}
В этом случае мы вводим ICommandLineRunner
в CLIService
и насмехаемся над вызовом RunCommand
, чтобы вернуть определенный вывод, который мы настроили заранее (содержимое нашего текстового файла). Этот подход позволяет нам проверить, что CLIService
делает правильный вызов к ICommandLineRunner
, и что он правильно анализирует вывод этого вызова. Если вам нужно, чтобы я что-то разъяснил об этом подходе, пожалуйста, дайте мне знать.