Mock both dependencies
The best solution is to Mock out both of your dependencies. Ideally your concrete class should have those dependencies injected upon construction.
You need to only test 3 things inside Process.
- Correct output of Process according to mocked inputs
- Behavior => (was dependency1.GetSomeList called as expected, etc)
- Corrcect output of Process along all logic paths
You should never use concrete dependencies, this will cause you to have fragile unit tests as you will be relying on data that is outside of your control. To test a method properly you need to provide invalid inputs (nulls, empty strings, extremely large numbers, negative numbers ) etc, anything in an attempt to break the current expected functinality. And naturally valid inputs as well.
You also do not need to replicate the actual functionality of your dependencies. The only thing you need to test is correct functionality of your code along all logic paths. If you need to change the output of dependency2 to test a 2nd code path. Then that's another test.
The advantage to separating your tests into a large number of finely grained tests cases is that if you change anything inside Process, and run your unit tests. You know exactly where the problem is because 3 / 50 tests now fail and you know where to fix your problems because they're all testing 1 specific thing.
Using Rhino Mocks would go something like this
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();
}
Update
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;
}
So effectively what happens above is that both of your processing is now broken up into separate objects. Process is not almost completely abstract (which is perfect). You can now test each element individually to ensure correct functionality in separate unit tests.
The above test will then become an Integration test where you test that each of the dependencies are called correctly.