4

It's often the case where I'd like to have multiple constructors in my controllers, since one of the constructors is optimal for manually injecting dependencies during unit testing and the other is optimal for using a IOC container to inject dependencies.

When using the standard service locator or DependencyResolver in MVC 3, is there any way to indicate to the controller factory which constructor to use when activating the controller?

I'd prefer not to use one of the attributes specific to an IOC framework since I want the code to remain independent of the IOC container.

UPDATE: It seems like the majority of the answers indicate its bad practice to have multiple constructors. I don't entirely disagree with this, however, the situation arises as a result of trying to find a good solution to the mapping/conversion layer, which I asked in this question but never got a good answer to.

My code would look like this:

public class SomeController : Controller
{
    private ISomeService _SomeService;
    private IEntityConverter _EntityConverter;

    // this would be used during unit tests when mocking the entity converter 
    public SomeController(ISomeService someService, IEntityConverter entityConverter)
    {
        _SomeService = someService;
        _EntityConverter = entityConverter;
    }

    // this would be used when injecting via an IOC container, where it would be tedious
    // to always specify the implementations for the converters
    public SomeController(ISomeService someService)
        : this(someService, new EntityConverter())
    {
    }

    public ActionResult Index(SomeViewModel someViewModel)
    {
        if (!ModelState.IsValid)
            return View(someViewModel);
        else
        {
            ServiceInput serviceInput = _EntityConverter.ConvertToServiceInput(someViewModel);
            _SomeService.DoSomething(serviceInput);
            return View("Success");
        }
    }
}

In this very simple example, I am using an interface to do conversions between my view models and the entities that are inputs to the service layer.

I'd prefer to use an interface because this conversion can be mocked, rather than if a static method was used. However, I feel like it would be tedious to always have to specify, in the IOC container, what the implementations are for these conversion implementations, since the implementations for these conversion interfaces sit right next to the interfaces.

This may not be the best solution. I'm open to better alternatives.

Community
  • 1
  • 1
Oved D
  • 7,132
  • 10
  • 47
  • 69

4 Answers4

4

Don't use multiple constructors. Your classes should have a single definition of what dependencies it needs. That definition lies in the constructor and it should therefore only have 1 public constructor.

I must say I'm not a fan of using mocking frameworks. I found that a good design of my application and my unit tests prevents me from having to use mocking frameworks all together (of course mileage may vary) .

One trick that helps me is allowing null references to be injected into the constructor by not validating the constructor arguments. This is very convenient for unit tests in cases where the class under test does not use the dependency, while in production you would still have the guarantee that null is not injected, since IOC containers will never inject null into a constructor (or at least none of the containers that I know).

Steven
  • 166,672
  • 24
  • 332
  • 435
  • when you say "I'm not a fan of using mocking frameworks" does that mean you write all test stubs by hand then? Isn't that tedious? – CRice Aug 03 '11 at 07:24
  • @CRice: In my experience it's not. I found the amount of stubs to write to be minimal and since they are most of the time very simple, it takes very little time to write. Besides that, mocking frameworks tend to obfuscate your tests, making them much harder to read (one of the [core qualities of good tests](http://osherove.com/blog/2009/12/31/rtm-ready-tests.html)). – Steven Aug 03 '11 at 07:29
  • Well whatever works for you. I think modern moq / rhino mocks syntax is much more simplistic and concise than in earlier versions. I sometimes still write stubs by hand to override virtual methods (in the same class under test), but still find benefit from the tools. – CRice Aug 03 '11 at 08:19
  • That google talk is pretty bad IMO, and I'll back that up by stating at the end it shows 4 people in the crowd... Specially when he discusses passing null to a constructor... – Phill Aug 03 '11 at 08:34
  • I would say it's not right to have the 'knowledge' of which dependencies are required for a specific test in your unit test. Why don't you just specify the normal dependencies to your class and only specify the adjustments? – thekip Aug 03 '11 at 11:52
  • @thekip: Injecting null has the benefit of tests to fail when the use of the dependencies is changes in the class under test (SUT). Sometimes the completeness of the test suite must be reevaluated when the class changes. Of course the creation of the SUT should in most cases be refactored to factory methods in the test class, to keep the test suite maintainable. – Steven Aug 03 '11 at 12:06
  • @Steveb; Please, enlighten me how good design prevents the need of mocks? I am using rhino mocks and stubs more and more frequently, as they isolate the object under test from surrounding dependcies. This, off course, assumes that dependencies should be injected from the outside, and not instantiated inside the class. Unless the logic of the stub/mock is very complex, I find it much easier to use a framework than to create my own stub. But, maybe I not seeing the big picture here? – Morten Aug 03 '11 at 14:49
  • 1
    @Morten: You need to use fake objects to test a class in isolation, no doubt. I define fake classes or on a test class basis and promote them to a project scope as needed. When you follow the SOLID principles correctly (especially the SRP, OCP, and ISP) and write [RTM tests](http://bit.ly/qHDK2Z) (must [read](http://amzn.to/pvpo6U)), you will find that that the fake classes will get very simple, which makes it very easy to create them by hand. The amount of (programming) overhead of these fake objects take is little enough for me to not use any mocking framework. I'll try to blog about it. – Steven Aug 03 '11 at 15:24
  • 2
    You shouldn't be passing null objects to a constructor and allowing your code to work. The whole point of constructor injection is to indicate the dependencies that are required for the class to function. If you allow nulls then this doesn't hold true. If you want to do the null scenario, you should be using property injection for the optional dependencies. – Oved D Aug 03 '11 at 15:28
  • @Oved D: Perhaps I didn't make myself clear. I'm not saying that your classes should be able to handle null references. My god I don't write `if (this.dep != null) { ... }` stuff; that would be bad. For that indeed the Null Object pattern exists. However, the constructors of services do not prevent null references from being injected. This allows me to pass null into the constructor during testing, in cases that I want to test part of the SUT that I know doesn't use that dependency. However, I must admit I don’t really use this all that often. – Steven Aug 03 '11 at 15:56
  • @Oved: [This Google Talk video](http://www.youtube.com/watch?v=RlfLCWKxHJ0) explains the usefulness of allowing to inject null references into constructors during tests. Take a look at the video. This topic is discussed at timeframes 23:50 and 35:00. – Steven Aug 06 '11 at 14:24
  • 1
    This does not answer the question. OP is not looking for ethical way but a workaround that is must sometimes. – deathrace Jul 24 '22 at 06:04
2

Seems like a code-smell that you need an explicit constructor for testing. What if the testing ctor works but the production one doesn't? Seems like a door for bugs to creep in. It would be ideal for tests to use the same path as real clients as far as possible.

What is different between the two ?

Also if you're using some sort of attribute based DI (e.g. like MEF), I'd not be too worried about decoupling. Having an extra attribute (and the corresponding reference) should not be that big a hit... unless you foresee a change in IOC tech in the future.

Gishu
  • 134,492
  • 47
  • 225
  • 308
  • I consider having your application code decoupled from the DI container to be important, but coupling to the DI can often simply be avoided by good design. Therefore I tend *not* to agree with your statement "not too be worried about decoupling". However, I completely agree with your statement about multiple constructors and like to add that having a production only constructor leaves part of the system untested, but leaves to extra production code bloat and makes the system a bit more complicated. +1 for your answer. – Steven Aug 03 '11 at 07:37
  • See my update above. I'm not that comfortable with the current solution and would love to hear a better one ;) – Oved D Aug 03 '11 at 15:25
  • @Over - since you have it as a parameter in your ctor-for-test, I assume IEntity.. isn't a test-friendly class. Hardwiring new SomeType() in your code defeats IOC. I'd prefer wiring your IOC logic to pass in EntityConverter for IEntityConverter OVER writing a second ctor – Gishu Aug 03 '11 at 17:26
  • @Steven - what I meant was that I'd like it decoupled as far as possible. But I wouldn't lose any sleep over it as long as it stays out of the way and doesn't *pollute* the production code and allows me to switch to something else within an hour or two. I was thinking about MEF where you just annotate classes for import/export. – Gishu Aug 03 '11 at 17:31
1

Maybe I'm misreading your question, but I'm not sure why you would want to test different constructors. The tests should test what's actually going to be used.

For your tests, you ought to mock your dependencies so that they don't need an IoC container.

Using Moq:

Controller:

public SomeController(IService1 service1, IService2 service2)
{
    // Do some cool stuff
}

Test Method:

[Test]
public void Some_Action_In_SomeController_Should_Do_Something()
{
    var service1Mock = new Mock<IService1>();
    var service2Mock = new Mock<IService2>();
    var controller = new SomeController(service1Mock.Object, service2Mock.Object);

    controller.Action();

    // Assert stuff
}
Chris
  • 4,393
  • 1
  • 27
  • 33
  • You say tests should test what's actually going to be used, but you use Moq, and isn't Moq just another way to break dependencies to real code? Not writing integration tests here - so no you should not test what's actually going to be used when it is an external dependency... Also, having multiple constructors does not mean there is any dependency at all on an IoC container. – CRice Aug 03 '11 at 07:15
  • I was referring to his constructors. If he has one constructor for testing and one for "production," he ought to be testing the constructor that will be used in "production." The OP then mentioned he didn't want to be coupled to a specific IoC container for his tests. Using mocks was my answer to that. That's definitely the beauty of this site though; if I say something that's wrong or "not the right way," not only does the OP learn something, so do I. :) – Chris Aug 03 '11 at 15:05
  • A bit more thinking about it and I see what you mean by not writing integration tests. Unit tests ought to be just on a single operation whereas relying on what the constructor does introduces something more than what the test could cover. I'll get the hang of this testing thing one of these days. :D – Chris Aug 03 '11 at 15:15
1

It's all to do with your service locator, you need to configure it where you register your types.

Here is an example of using the default parameterless constructor when using Unity.

Note that by default the service locator will use the most specific constructor (the one with the most parameters)

ServiceLocator.Current.RegisterType<ICache, HttpContextCache>(new InjectionConstructor()); //use default constructor

So why did I need this? It is true I could have made a protected virtual method to resolve HttpContextBase and use extract and override in the test, or otherwise yet another interface with a method that creates the HttpContextBase that can be injected into this class.... or I could just tell unity to use the default constructor.

    private readonly HttpContextBase _httpContextBase;

    public HttpContextCache()
    {
        _httpContextBase = new HttpContextWrapper(HttpContext.Current);
    }

    public HttpContextCache(HttpContextBase httpContextBase)
    {
        _httpContextBase = httpContextBase;
    }

This was a rare case and pretty much all other classes in the project have only one constructor

CRice
  • 12,279
  • 7
  • 57
  • 84