0

I'm trying to wtire unit tests for a function that looks something like this:

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

        //Do some more processing
        int processedInt = this.dependency2.DoSomeProcessing(element);

        // ... Do some processing to processedInt

        outputList.Add(processedInt);
    }
    return outputList;
}

I was planning on mocking dependency1 and dependency2 in the test cases but I'm not sure how I should set them up. In order to setup dependency2.DoSomeProcessing I will need to know what the value of "element" will be each time it is called. To figure this out I would either need to:

  1. Copy paste some of the logic from my Process() method into the test case

  2. Calculate the values by hand (in the actual function this would involve hard coding some doubles with many decimal places into the test case)

  3. Bite the bullet and use the actual implementation of dependency2 instead of mocking it.

None of these solutions seem very good to me. I'm new to IOC and mocking so I'm hoping there's just something I'm completely not getting. If not which of these solutions seems the least bad?

Thanks

Edit: I'm using Moq to mock the dependencies.

rob
  • 17,995
  • 12
  • 69
  • 94

4 Answers4

1

Is the variable "element" changed between the begin of foreach and DoSomeProcessing(element) method? If not, I would go with option number 2. Since you have the control over dependency1 and dependency2, you can create a stub for them so you return some elements in the list and you write code in dependency2 to handle each of the elements you got from dependency1 and return the correct integer.

My second option would be 3. I didn't like the first one.

By the way, look if Pex (http://research.microsoft.com/en-us/projects/pex/) can be useful for you in this case, since you have the actual code done.

[]'s

Fabio
  • 3,020
  • 4
  • 39
  • 62
1

What exactly are you testing?

The content of this method is that it calls one function to get a list of values, then calls another function to modify these values and returns the modified values.

You should not be testing the logic that gets the values, or the logic that converts it in this test, they are seperate tests.

So your mocking should be something like (hand compllied with Moq)

var dependency1 = new Mock<IDependency1>()
  .Setup(d => d.GetSomeList(It.IsAny<int>())
  .Returns(new List<int>(new [] { 1, 2, 3 });  
var dependency2 = new Mock<IDependency2>()
  .Setup(d => d.DoSomeProcessing(It.IsAny<int>())
  .Returns(x => x * 2); // You can get the input value and use it to determine an output value

Then just run your method and make sure the returned list is 2,4,6. This validates that some processing was performed on some list.

You then create a different test that makes sure GetSomeList() works. And another that makes sure DoSomeProcessing() works. Its the DoSomeProcessing() test that will require hand calculated values.

Chris Sainty
  • 9,086
  • 1
  • 26
  • 31
  • Ah I didn't know you can base the return value off the input in Moq. The actual function signature looks more like this: bool Evaluate(input1, input2, out output) So how would i base output off of input1 and input2? Or could you point me in the direction of the moq documentation that addresses this? Thanks! – rob Jul 21 '11 at 02:27
  • @rob .Returns((int p1, int p2)=> p1 * p2); Outs are a different matter. See here http://stackoverflow.com/questions/1881132/mock-an-out-parameter-with-moq-or-rhino-mock-or-something-else you shouldnt really need to worry about the input though, you are just trying to get a value into the output that you can test against and know that the code was fired. – Chris Sainty Jul 21 '11 at 02:52
  • Thanks for the link. That's a bummer Moq doesn't support mocking out parameters. But if I ignore the input then I will be ignoring some of the logic that came before "DoSomeProcessing()" and I won't be able to test that it was done correctly. – rob Jul 21 '11 at 03:14
  • I think I'll just do it this way and change my function so that it doesn't have any out parameters. Thanks! – rob Jul 21 '11 at 13:40
1

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.

  1. Correct output of Process according to mocked inputs
  2. Behavior => (was dependency1.GetSomeList called as expected, etc)
  3. 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.

Justin Shield
  • 2,390
  • 16
  • 12
  • Thanks. I haven't used Rhino Mock before but it looks like your sample code assumes that the input to DoSomeProcessing is always 0 which is not the case. It is that input that I'm not sure how to calculate. Although based on Chris's answer it looks like I might not have to calculate it... – rob Jul 21 '11 at 02:40
  • In this case the input is irrelevant, and so Rhino is told to IgnoreArguments and return 1 (0 is only placed there as a placeholder as you can't give null for an integer). The only thing you need to test is not HOW Process performs its actions, only that it gives you the correct answer in its output. IMHO it looks like you should be abstracting away ProcessElement and ProcessInt into two separate testable methods/functions and unit test these separately so you can validate that given an input of X it produces Y. – Justin Shield Jul 21 '11 at 02:44
  • If I ignore the input then won't that be ignoring some important logic that I want to test. I could break this up into two methods but it wouldn't really make sense to make both of them public. So it would be a bit of a hack to test the inner protected one. – rob Jul 21 '11 at 03:22
  • It does make sense to make them public, only not to this particular object. I'll update the answer with what I mean. – Justin Shield Jul 21 '11 at 03:35
  • Ah I understand what you mean now. – rob Jul 21 '11 at 03:54
1

Okay, so first of all if you have access to this method and can change it then a much better approach would be the following:

public IEnumerable<int> Process(int input)
{
    foreach(var element in dependency1.GetSomeList(input))
    {
        yield return dependency2.DoSomeProcessing(element);
    }
}

So now on to the question at hand. You have 2 dependencies in the method that need to be mocked in order to test it properly. There are a few good ways of doing this but the simplest is to use Constructor Dependency Injection. This is where you inject the dependency into your class through the constructor. You will need your dependencies to have a common base type (interface or abstract class) to perform the injection too.

public class Processor
{
    public Processor(IDep1 dependency1, IDep2 dependency2)
    {
        _dependency1 = dependency1;
        _dependency2 = dependency2;
    }

    IDep1 _dependency1;
    IDep2 _dependency2;

    public IEnumerable<int> Process(int input)
    {
        foreach(var element in dependency1.GetSomeList(input))
        {
            yield return dependency2.DoSomeProcessing(element);
        }
    }
}

Now create a mock to inject into it for your tests.

public interface IDep1
{
    IEnumerable<int> GetSomeList(int);
}

public interface IDep2
{
    int DoSomeProcessing(int);
}

public class MockDepdency1 : IDep1
{
    public IEnumerable<int> GetSomeList(int val)
    {
        return new int[]{ 1, 2, 3 }.AsEnumerable();
    }
}

public class MockDepdency2 : IDep2
{
    public int DoSomeProcessing(int val)
    {
        return val + 1;
    }
}

...
main()
{
    IDep1 dep1 = new MockDependency1();
    IDep2 dep2 = new MockDependency2();

    var proc = new Processor(dep1, dep2);
    var actual = proc.Process(5);

    Assert.IsTrue(actual.Count() == 3);
}

I haven't written this code in the compiler - I just typed it in by hand but it should be close to working and represents a good example of how you could test that method.

An even better way is to use a utility like Unity and don't inject through the constructor. Instead you can just map your interface to the MockDependency1 and MockDependency2 inside your test and when Process(...) runs it will get the Mock versions instead. If you want to know how to do that then let me know and I'll add it below.

phillip
  • 2,618
  • 19
  • 22
  • I think this will work. I probably should have mentioned that I am doing the mocking with Moq. The thing I was getting hung up on was that I thought you had to specify the literal input to a mocked method when you were setting it up which it turns out is not the case. But I still haven't figured out to generate the output and "out" parameters off of the input in Moq... – rob Jul 21 '11 at 03:01
  • 1
    The idea of using dependencies is so they can be abstracted away from the code we want to test. Abstracting them away means that they can be removed from the equation, their inputs into the equation carefully weighed and the output of the equation tested for correctness. As soon as we manually create a mock object (as above) we are now creating a tight coupling between the dependencies and the method in question. If the functionality of either of the dependencies change, you unit test breaks because our mock object is no longer in sync with the real object that it is trying to emulate. – Justin Shield Jul 21 '11 at 03:03
  • +1 from me... I can't disagree but it's still a great way to do it if you don't want to learn a mocking framework. Moq is my preferred framework - and I like TypeMock as well. – phillip Jul 21 '11 at 05:37