Макет обеих зависимостей
Лучшее решение - отключить обе ваши зависимости. В идеале ваш конкретный класс должен иметь эти зависимости, вводимые при построении.
Вам нужно протестировать только 3 вещи внутри процесса.
- Правильный вывод процесса в соответствии с проверенными входами
- Behavior => (была зависимость.GetSomeList вызывается как положено и т. Д.)
- Исправить вывод Process по всем логическим путям
Вы никогда не должны использовать конкретные зависимости, это приведет к тому, что у вас будут хрупкие юнит-тесты, так как вы будете полагаться на данные, которые находятся вне вашего контроля. Чтобы правильно протестировать метод, вы должны предоставить недопустимые входные данные (нули, пустые строки, чрезвычайно большие числа, отрицательные числа) и т. Д., Что-либо в попытке нарушить текущую ожидаемую функциональность. И, естественно, действительные входные данные.
Вам также не нужно копировать фактическую функциональность ваших зависимостей. Единственное, что вам нужно проверить - это корректная работа вашего кода по всем логическим путям. Если вам нужно изменить вывод зависимости, чтобы проверить второй путь кода. Тогда это еще один тест.
Преимущество разделения ваших тестов на большое количество мелкозернистых тестовых случаев состоит в том, что если вы что-то измените внутри Process и запустите свои модульные тесты. Вы точно знаете, в чем проблема, потому что 3/50 тестов теперь не проходят, и вы знаете, где исправить ваши проблемы, потому что все они тестируют 1 конкретную вещь.
Использование Rhino Mocks будет примерно таким
private IDependency1 _dependency1;
private IDependency2 _dependency2;
private ClassToBeTested _classToBeTested;
[SetUp]
private override void SetUp()
{
base.SetUp();
_dependency1 = MockRepository.GenerateMock<IDependency1>();
_dependency2 = MockRepository.GenerateMock<IDependency2>();
_classToBeTested = new ClassToBeTested(_dependency1, _dependency2);
}
[Test]
public void TestCorrectFunctionOfProcess()
{
int input = 10000;
IList<int> returnList = new List<int>() {1,2,3,4};
// Arrange
_dependency1.Expect(d1 => d1.GetSomeList(input)).Return(returnList);
_dependency2.Expect(d2 => d2.DoSomeProcessing(0))
.AtLeastOnce().IgnoreArguments().Return(1);
// Act
var outputList = _classToBeTested.Process(input);
// Assert that output is correct for all mocked inputs
Assert.IsNotNull(outputList, "Output list should not be null")
// Assert correct behavior was _dependency1.GetSomeList(input) called?
_dependency1.VerifyAllExpectations();
_dependency2.VerifyAllExpectations();
}
Обновление
IElementProcessor _elementProcessor;
public List<int> Process(int input)
{
List<int> outputList = new List<int>();
List<int> list = this.dependency1.GetSomeList(input);
foreach(int element in list)
{
// ... Do some procssing to element
_elementProcessor.ProcessElement(element);
//Do some more processing
int processedInt = this.dependency2.DoSomeProcessing(element);
// ... Do some processing to processedInt
_elementProcessor.ProcessInt(processedInt);
outputList.Add(processedInt);
}
return outputList;
}
То, что происходит выше, настолько эффективно, что обе ваши обработки теперь разбиты на отдельные объекты. Процесс не является почти полностью абстрактным (что идеально). Теперь вы можете тестировать каждый элемент отдельно, чтобы гарантировать правильную функциональность в отдельных модульных тестах.
Приведенный выше тест станет интеграционным тестом, в котором вы проверяете, что каждая из зависимостей вызывается правильно.