2

I'm using dependency injection to supply one of my classes (SomethingManager) with something it needs (SomethingEngine). In the constructor of the SomethingManager I set some properties on SomethingEngine. SomethingManager then exposes a set of methods which wrap up calls to SomethingEngine as well as some small bits of logic. I would like to unit test my constructor to test the logic of the properties I set initially and also to ensure the correct properties are set. In order to examine the results of my tests I'm looking at exposing a get accessor to ISomethingEngine on the SomethingManager but this doesn't seem like a nice solution.

What is a better way to do this?

private IEngine _engine;
public Manager(IEngine engine)
{
    _engine = engine;
    _engine.Prop1 = "a"; //etc
}

Now in order to test I really need to make IEngine public (or at least internal) and mark it visible to my unit test project

3
  • 3
    Is this just to get a reference to the engine inside the unit test? If you inject the engine as a dependency in the unit test you should already have this reference..
    – JacquesB
    Commented Jul 31, 2017 at 14:08
  • Where is IEngine defined and how do you create an engine to inject into Manager?
    – Peter M
    Commented Jul 31, 2017 at 15:07
  • There is always InternalsVisibleTo and internal if you want to test implementation details (I typically only need it for public methods on internal types, not internal fields/methods on public types). Commented Jul 31, 2017 at 15:08

4 Answers 4

5

Test the unit under test, mock or stub the rest.

In this case you want to test the SomethingManager constructor. In that case you would pass it a mock SomethingEngine. Record in the mock SomethingEngine what SomethingManager calls on it, then verify the right calls were made.

2
  • That is what I'm doing but in order to test what properties I've set on the SomethingEngine I need to expose that as a property on SomethingManager. And thats the only reason that property will exist => to satisfy unit tests. Which I believe is not good practice. Pre-writing the test, the SomethingEngine was just private
    – user48408
    Commented Jul 31, 2017 at 14:20
  • 1
    Maybe we're getting our lingo mixed up. If you mean that you have an accessor on SomethingManager that fetches a property from SomethingEngine and relays it, then that shouldn't be necessary because in the unit test you have a direct handle to SomethingEngine. If instead you mean that you have made SomethingEngine a public inner class instead of a private inner class, then perhaps the solution is to make the interface to it public, but not the implementation. Commented Jul 31, 2017 at 14:42
0

Sounds to me like you might be testing the wrong things.

Tests should verify that, given a certain input, the correct output is achieved. How a given function arrives at a correct output is (mostly) irrelevant.1 Let's say your SomethingManager class looks like this:

public class SomethingManager
{
    //...
    public int DoFoo(int x) { ... }
    //...
}

And let's say that the following should be true for DoFoo

Input | Output
--------------
1     | 5
2     | 6
3     | 7

One possible implementation of DoFoo would be this:

public int DoFoo(int x)
{
    if (x == 1) return 5;
    if (x == 2) return 6;
    return 7;
}

Or you could do this:

public int DoFoo(int x)
{
    return x + 4;
}

Either of those implementations achieve the desired behavior, so both implementations of DoFoo fulfill the contract and work as intended (as defined by the 3 inputs/outputs above). Which is correct? Depends on what you are trying to achieve. But if how you go about achieving your goal changes for whatever reason, the tests should still pass.

So is it really important to know that your constructor sets a property on a dependency? I should hope not. That seems to be more of testing the "how it does" rather than the "what it should do".


1You might design tests to cover corner / edge cases of a given implementation, but if the implementation changes, those tests are still valid.

0

Consider setting SomethingEngine properties in a factory method for SomethignManager and passing it configured to the constructor. This seperates SomethingEngine configuration from SomethingManager construction, which allows testing SomethingEngine configuration seperately.

For example:

class Manager {
    private IEngine _engine;

    //private constructor to allow only properly configured engines
    Manager(IEngine engine) {
        _engine = engine;
    }

    public void ConfigureEngine(IEngine engine) {
        engine.Prop1 = "a";
        //etc
    }

    public static Manager Create(IEngine engine) {
        ConfigureEngine(engine);
        return new Manager(engine);
    }
}

This allows for unit testing the ConfigureEngine method.

0

Write a stub that conforms to the IEngine interface. You can add as many accessors to that stub that you want. Then inject the stub. Test to see if the Manager calls the stub the way you expect.

class TestEngine : IEngine
{
    public string Prop1 { get; set; } //You can do this even if get isn't in the interface
}

//Arrange
var e = new TestEngine();

//Act
var m = new Manager(e);

//Assert
Assert.AreEqual("a", e.Prop1);

Not the answer you're looking for? Browse other questions tagged or ask your own question.