Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I correctly unit test methods that depend on each other?

Consider this code:

    private readonly Dictionary<Type, Component> _components = new Dictionary<Type, Component>();

    public Component this [Type type]
    {
        get
        {
            Component component;
            _components.TryGetValue(type, out component);
            return component;
        }
    }

    public void AddComponent(Component component)
    {
        _components.Add(component.GetType(), component);
    }

As you can see, AddComponent adds to the private _components variable. But the only way to test this is happening is by using the indexer. That's fine, but in order to test the indexer I'd have to call AddComponent too!

In other words, in the unit tests for the indexer and AddComponent, each test would have to call both of these methods. It seems like this is creating unnecessary coupling. If there is a bug in the indexer, there is no reason for my TestAddComponent to fail.

What is the best practice here? Do I use reflection to get at _components? Mocking? Something else?

like image 652
ryeguy Avatar asked May 11 '11 03:05

ryeguy


4 Answers

In my opinion, unit tests shouldn't do reflection to force it's goals. I think that in this kind of test, both should be tested toghether, in the same test. But that is just a point of view.

However, you can make multiple tests, changing the order of the instructions. Try to add multiple, and the access the first, then the last, then one from the middle. Each test, is one scenario, with different order, number of insertions. You can even test exceptional states that must happen... for example, if you try to get something that was not inserted.

I think that unit test exists to mimic usage, or to enforce specification. Not to see if every single bit of the program is right, because that kills flexibility.

like image 181
Miguel Angelo Avatar answered Oct 13 '22 12:10

Miguel Angelo


Well you have 2 options:

  1. Use reflection or the MSTest private accessor classes to get and set private field values during your test.
  2. Just don't worry about it and test the exposed behaviour, even if that means your test depends on other properties or method that are being tested elsewhere.

As you can probably tell from the wording, my choice would be with #2 - You should test the exposed behaviour. In your case the exposed behaviour that you are testing is:

  • If I use AddComponent then the added component should be accessible through the indexer
  • If I use the indexer, I should be able to access any components that were added through AddComponent

In this case its fairly obvious that these are pretty much the same thing, so we only really have one unit case / exposed behaviour to test here. Yes this unit test covers two different things, but that shouldn't really matter - we aren't trying to test that each method / property behaves as expected, rather we want to test that each exposed behaviour works as expected.


As an alternative, suppose that we go for option 1 and used private reflection to check the state of _components ourselves. In this case the bevahour that we are actually testing is:

  • If I use AddComponent then the added component should be added to _components
  • If I use the indexer, I should be able to access any components that are in _components

Not only are we now testing the internal behaviour of the class (so that if the implementation changes the tests fail, even if the class is working as expected), but we have just doubled the number of tests we are writing.

On top of that, by increasing the complexity of our tests we are increasing the chance that the tests themselves have a bug - for example what if we made a mistake and in test 2. we checked some completely different private field? In this case not only have we made more work for ourselves, but we aren't even testing the actual behaviour that we want to test!

like image 31
Justin Avatar answered Oct 13 '22 14:10

Justin


When you're using Microsoft Unit Test Framework, the framework generates a private accessor class. This should allow you to access your private types. Take a look at this page from Microsoft for more info:

http://msdn.microsoft.com/en-us/library/dd293546.aspx

Specially this section: Create unit tests that can access internal, private, and friend methods.

like image 21
Wagner Silveira Avatar answered Oct 13 '22 12:10

Wagner Silveira


May I suggest using interfaces and or virtual methods and MOQ. That way you can MOQ the calls to the methods you are not wanting to test and make them return what you want.

like image 32
mluker Avatar answered Oct 13 '22 14:10

mluker