I have a function that iterates through a list of parent objects and fetches child objects for each parent object in a for-each loop. To get the list of child objects, the function calls another function. Here is the function:

public IEnumerable<IParentObject> GetParentAndChildObjects()
{
    var parentObjects = new List<ParentObject>();

    foreach (var item in _dbRepository.GetParentObjects())
    {
        var parentObject = new ParentObject() { Id = item.ID, Name = item.Name };
        foreach (var subItem in _dbRepository.GetChildObjects(item.ID))
        {
            parentObjects.Children.Add(new ChildObject() { Id = subItem.ID, Name = subItem.Name });
        }
    }
    return parentObjects;
}

How do I write Unit Test for this function? I am using Moq for mocking.

有帮助吗?

解决方案 2

Something like this:

var repo = new Mock<MyRepository>();
repo.Setup(r => r.GetParentObjects()).Returns(... a list with a couple of parent objects ...);
repo.SetUp(r => r.GetChildObjects(... id of first parent ...)).Returns(... list of child objects ...);
repo.SetUp(r => r.GetChildObjects(... id of secondparent ...)).Returns(... different list of child objects ...);

var result = new MyClass(repo.Object).GetParentAndChildObjects();

... assertions to check 2 parents with appropriate children returned ...

其他提示

One approach you could use is to test the inner loop in the same way you would a private method. That is, you don't (at least, not directly).

Instead of testing the loop itself, verify the result that is returned by GetParentAndChildObjects.

By designating a test double for _dbRepository, you have complete control over the details of the objects that are inserted into the parentObjects list. As a result, your test can just verify that the returned list of objects looks as expected.

Mark Seemann describes this approach well:

After having answered the question on when to use [stubs and when to use mocks], a couple of times, I arrived at this simple rule, based on the language of Command Query Separation (CQS):

  • Use Mocks for Commands

  • Use Stubs for Queries

This makes lots of sense, because Commands are all about side effects, and Mocks are all about Behaviour Verification: that is, that side effects occurred. Stubs, on the other hand, mainly exist to 'make happy noises', and one of the ways they have to do that, is to return data from dependencies, when return data is required.

Typically, you would create a function for the inner loop (probably a good thing to do anyway, for readability and nesting). Then, once that function is in place, you can create unit tests for it just as you would for any other method.

If, for some reason you do not want to use "Extract Method" refactoring (which can be automated with Resharper or other refactoring tools), I'm afraid you are out of luck, because unit tests need to have an entry point to test and you cannot enter in the middle of another method.

One thing you might consider, though it is more maintenance, is to have one debug-version for the unit tests, and an optimized version with the loop inlined, using #if. If you are on .NET 4.5 or higher, you can simply extract the inner loop as a method and use aggressive inlining of the method, and you don't have the overhead of high maintenance of (potential) loss or performance of the extracted method.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top