8

Shorter version of the rest of the question: I've got a problem, and an IoC container is a tool. The problem sounds like something IoC might be able to solve, but I haven't read enough of the tool's instructions to know for sure. I'm curious if I picked the wrong tool or which chapter of the instruction manual I might be able to skip to for help.

I work on a library of Windows Forms controls. In the past year, I've stumbled into unit testing and become passionate about improving the quality of our automated tests. Testing controls is difficult, and there's not much information about it online. One of the nasty things is the separation of interaction logic from the UI glue that calls it leads to each control having several more dependencies than I would normally consider healthy for a class. Creating fakes for these elements when testing their integration with the control is quite tedious, and I'm looking into IoC for a solution.

There's one hurdle I'm not sure how to overcome. To set up the container, you need to have some bootstrapper code that runs before the rest of the application. In an application there is a very clear place for this stuff. In a library it's not so clear.

The first solution that comes to mind is creating a class that provides a static instance of the container and sets up the container in its type initializer. This would work for runtime, but in the test environment I'm not sure how well it would work. Tests are allowed to run in parallel and many tests will require different dependencies, so the static shared state will be a nightmare. This leads me to believe the container creation should be an instance method, but then I have a chicken and egg problem as a control would have to construct its container before it can create itself. The control's type initializer comes to mind, but my tests won't be able to modify this behavior. This led me to think of making the container itself a dependency of the control where user-visible constructors provide the runtime default implementation, but this leaves it up to my tests to set up their own containers. I haven't given this much thought, but it seems like this would be on the same level of effort as what I have now: tests that have to initialize 3-5 dependencies per test.

Normally I'd try a lot of things on my own to see what hurts. I'm under some harsh deadlines at the moment so I don't have much time to experiment as I write code; I only get brief moments to think about this and haven't put much to paper. I'm sure someone else has had a similar problem, so it'd be nice if I didn't have to reinvent the wheel.

Has anyone else attacked this problem? Are there some examples of strategies that will address these needs? Am I just a newbie and overcomplicating things due to my inexperience? If it's the latter, I'd love any resources you want to share for solving my ignorance.

Update:

I'd like to respond to Mark Seeman's answer, but it will require more characters than the comment field allows.

I'm already toying with presentation model patterns. The view in this case is the public control class and each has one or more controller classes. When some UI event is triggered on the control, the only logic it performs is deciding which controller methods need to be called.

The short expression of an exploration of this design is my controller classes are tightly coupled to their views. Based on the statement that DI containers work with loosely coupled code I'm reading "wrong tool for the job". I might be able to design a more loosely coupled architecture, at which point a DI container may be easier to use. But that's going to require some significant effort and it'd be an overhaul of shipped code; I'll have to experiment with new stuff before tiptoeing around the older stuff. That's a question for another day.

Why do I even want to inject strongly coupled types rather than using local defaults? Some of the seams are intended to be extensibility points for advanced users. I have to test various scenarios involving incorrect implementations and also verify I meet my contracts; mock objects are a great fit.

For the current design, Chris Ballard's suggestion of "poor man's DI" is what I've more or less been following and for my strongly coupled types it's just a lot of tedious setup. I had this vision that I'd be able to push all of that tedium into some DI container setup method, but the more I try to justify that approach the more convinced I become that I'm trying to hang pictures with a sledgehammer.

I'll wait 24 hours or so to see if discussion progresses further before accepting.

OwenP
  • 24,950
  • 13
  • 65
  • 102
  • FWIW Windows Forms isn't the easiest technology on which to implement loosely coupled UI code. However, you may find the following discussion helpful: http://stackoverflow.com/questions/2128588/using-ninject-to-inject-dependencies-into-externally-constructed-objects-user-co – Mark Seemann Apr 02 '11 at 11:31
  • Choosing an answer to accept was difficult. Mark Seemann is philosophically correct. However, my time constraints don't allow for an attempt to redesign *and* I'm trying to shoehorn new features into legacy code. I'm adopting Chris Ballard's suggestion of poor man's DI while letting default constructors use runtime defaults. I'm not claiming it's right, but it's what I've chosen. – OwenP Apr 06 '11 at 18:59

3 Answers3

5

Dependency Injection (Inversion of Control) is a set of principles and patterns that you can use to compose loosely coupled code. It's a prerequisite that the code is loosely coupled. A DI Container isn't going to make your code loosely coupled.

You'll need to find a way to decouple your UI rendering from UI logic. There are lots of Presentation Patterns that describe how to do that: Model View Controller, Model View Presenter, Presentation Model, etc.

Once you have good decoupling, DI (and containers) can be used to compose collaborators.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
4

Since the library should not have any dependency on the ioc framework itself we included spring.net ioc config xml-files with the standard configuration for that lib. That was modular in theory because every dll had its own sub config. All sub-configs were then assembled to become a part of the main confing.

But in reality this aproach was error prone and too interdependent: one lib config had to know about properties of others to avoid duplicates.

My conclusion: either use @Chris Ballard "poor man's dependency injection" or handle all dependencies in on big ugly tightly coupled config-module of the main app.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
k3b
  • 14,517
  • 7
  • 53
  • 85
2

Depending on how complex your framework is, you may get away with handcoding constructor based dependency injection, with a parameterless default constructor (which uses the normal concrete implementation) but with a second constructor for injecting the dependency for unit test purposes, eg.

private IMyDependency dependency;

public MyClass(IMyDependency dependency)
{
    this.dependency = dependency;
}

public MyClass() : this(new MyDefaultImplementation())
{

}
Chris Ballard
  • 3,771
  • 4
  • 28
  • 40