views:

85

answers:

5

I have a class Foo that uses another class Bar to do some stuff.

I'm trying to do test driven development, and therefore am writing unit tests for Foo to make sure it calls the appropriate methods on Bar, and for this purpose I'm using dependency injection and mocking Bar (using Rhino Mocks).

E.g. (in C#):

class Foo
{
  private IBar bar= null;

  public Foo(IBar bar)
  {
    this.bar= bar;
  }

  public void DoSomething()
  {
    bar.DoIt();
  }
}

class FooTests
{
  ...
  void DoSomethingCallsBarsDoItMethod()
  {
    IBar mockBar= MockRepository.GenerateMock<IBar>();
    mockBar.Expect(b=>b.DoIt());    
    Foo foo= new Foo(mockBar);
    foo.DoSomething();
    mockBar.VerifyAllExpectations();
  }
}

This all seems to be fine, but I actually want Bar to be configured with a particular parameter, and was going to have this parameter passed in via Foo's constructor. E.g. (in C#):

public Foo(int x)
{
  this.bar = new Bar(x);
}

I'm not sure which is the best way to change this to be more easily testable. One options I can think of involves moving the initialization of Bar out of its constructor, e.g.

public Foo (IBar bar, int x)
{
  this.bar= bar;
  this.bar.Initialize(x);
}

I feel that this is making Bar harder to use though.

I suspect there may be some kind of solution that would involve using an IoC container configured to inject Foo with a mock IBar and also provide access to the created mock for expectation validation, but I feel this would be making Foo unnecessarily complex. I'm only using dependency injection to allow me to mock the dependencies for testing, and so am not using IoC containers at present, just constructing dependencies in a chained constructor call from the default constructors (although I realize this is creating more untested code) e.g.

public Foo() :
  this(new Bar())
{
}

Can anyone recommend the best way to test dependent object construction/initialization?

+1  A: 

Define this variable x in your dependency injection framework, and inject it to both Foo and Bar.

Sjoerd
A: 

How is Foo created? Is it coming from an inversion of control container? If so you may be able to use features in your IoC container to configure these objects.

If not, just bite the bullet and add a method Foo.Initializer(parameter) which calls Bar.Initialize(parameter) or perhaps takes an instance of Bar.

I haven't been doing unit testing that much longer then you, but I've found I don't do things in constructors anymore. It just gets in the way of testing. A constructor takes the objects dependencies, then its done.

Frank Schwieterman
Foo isn't coming from an IoC container at the moment. The separate initializers solution is the one I have been leaning towards for now. Another downside to this would be having to litter all other public methods with asserts and/or exceptions to guard against use of uninitialized objects, when that wouldn't be required if the constructor could do the initialization. Thanks.
Ergwun
+1  A: 

It seems to me that you are letting an implementation detail leak through the API design. IBar shouldn't know anything about Foo and its requirements.

Implement Bar with Constructor Injection just like you did with Foo. You can now make them share the same instance by supplying it from the outside:

var x = 42;
IBar bar = new Bar(x);
Foo foo = new Foo(bar, x);

This would require your Foo constructor to look like this:

public class Foo
{
    private readonly int x;
    private readonly IBar bar;

    public Foo(IBar bar, int x)
    {
        if (bar == null)
        {
            throw new ArgumentNullException("bar");
        }

        this.bar = bar;
        this.x = x;
    }
}

This allows Foo to deal with any implementation of IBar without letting the the implementation details leak through. Separating IBar from x can be viewed as an implementation of the Interface Segregation Principle.

In DI Container terminology, x can be viewed as being Singleton-scoped (not to be confused with the Singleton design pattern) because there is only a single instance of x across many different components. The instance is shared and it is strictly a lifetime management concern - not an API design concern.

Most DI Containers have support for defining a service as a Singleton, but a DI Container is not required. As the above example shows, you can also wire shared services up by hand.

In the cases where you don't know the value of x until run-time, Abstract Factory is the universal solution.

Mark Seemann
Foo doesn't care about x, except for the fact that Bar must be initialized with it. I've edited my question to clarify this. Thanks.
Ergwun
@Ergwun: If Foo doesn't care about x then just create Bar with x and inject it into Foo. If x can't be know until run-time, use an Abstract Factory to create IBar in Foo - see the last link of my answer.
Mark Seemann
After trying it out for a while, I have found this use of the abstract pattern factory to be extremely helpful for this kind of problem. Thanks!
Ergwun
A: 

This is more a question about design. Why does Foo need Bar initialized with a particular value of x? Potentially the class boundaries are not defined optimally. Maybe Bar shouldn't encapsulate the value of x at all, just take it as a parameter in the method call:

class Foo
{
  private IBar bar= null;
  private int x;

  public Foo(IBar bar, int x)
  {
    this.bar= bar;
    this.x = x;
  }

  public void DoSomething()
  {
    bar.DoIt(x);
  }
}

If for some reason you can't change the design I think I would just have an assertion in the constructor:

class Foo
{
  private IBar bar= null;

  public Foo(IBar bar)
  {
    if(bar.X != 42) 
    {
      throw new ArgumentException("Expected Bar with X=42, but got X="+bar.X);
    }
    this.bar= bar;
  }

  public void DoSomething()
  {
    bar.DoIt();
  }
}

This example also shows that you need to have some integration tests to make sure all the individual classes are correctly integrated with each other :)

Grzenio
To give a bit more background, Bar is actually responsible for sequencing messages, and according to the existing protocol, the initial sequence number is configurable. Foo.DoSomething() will actually be passing messages and sequence numbers, which Bar uses to order messages before processing.
Ergwun
But why does Foo need to know about the initial number?
Grzenio
Grzenio, Foo doesn't need to know it, except for the fact that I had Bar constructed with it indside Foo. I could have it passed to Bar outside of the constructor, but have gone down the abstract factory pattern approach suggested in another answer. Thanks.
Ergwun
A: 

I'd just overload the constructor, have one that accepts x, another that accepts a Bar.

This makes your object easier to use and easier to test.

//containing class omitted
public Foo(Bar bar) {
    this.bar = bar;
}

public Foo(int x) {
    this(new DefaultBar(x));
}

This is what constructor overloading was invented for.

iwein
I can't see how either of these constructors makes it esay for me to test that Foo correctly initializes Bar. In the former Foo is not initilizing Bar, and in the latter Bar cannot be mocked.
Ergwun