2

When trying to unit test my web api project I am getting the error

{[Message, An error has occurred.]} ExceptionMessage, An error occurred when trying to create a controller of type 'ExampleController'. Make sure that the controller has a parameterless public constructor. {[ExceptionType, System.InvalidOperationException]} {[StackTrace, at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()]} {[InnerException, System.Web.Http.HttpError]}

Unit Test:

[TestFixtureSetUp]
public void TestsSetup()
{
    _server = HttpRequestHelper.SetupHttpServerDefault();
}

[Test]
public void CanGetAllAddresses()
{
    var client = new HttpClient(_server);

    var request = HttpRequestHelper.CreateRequest("memory/address", HttpMethod.Get, ConfigurationManager.AppSettings["KeyUser"], string.Empty, ConfigurationManager.AppSettings["SecretUser"]);
    using (HttpResponseMessage response = client.SendAsync(request).Result)
    {
        Assert.NotNull(response.Content);
    }
}

I am registering my controllers within an nunit TestFixtureSetUp function that involves this logic:

public static HttpServer SetupHttpServerDefault()
{
    var config = new HttpConfiguration();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "memory/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    var container = new Container();
    container.Register<IAddressService, AddressService>();
    var services = GlobalConfiguration.Configuration.Services;
    var controllerTypes = services.GetHttpControllerTypeResolver().
            GetControllerTypes(services.GetAssembliesResolver());
    foreach (var controllerType in controllerTypes)
    {
      var registration = Lifestyle.Transient.
          CreateRegistration(controllerType, container);

      container.AddRegistration(controllerType, registration);

      registration.SuppressDiagnosticWarning
                   (DiagnosticType.DisposableTransientComponent, "");
    }
    container.Verify();
    GlobalConfiguration.Configuration.DependencyResolver = new 
                    SimpleInjectorWebApiDependencyResolver(container);
    return new HttpServer(config);
}

My address controller starts out like this:

public class AddressController : BaseController
{
    private readonly IAddressService _addressService;

    public AddressController(IAddressService addressService)
    {
        _addressService = addressService;
    }
}

When removing the controller parameters I am able to debug into the controller which tells me I am not injecting the dependencies into the controller correctly. I've looked over this post here that seems similar but I am unfamiliar with how I would explicitly declare my controllers. I tried using a similar method to my services but I did not work.

Eric G
  • 2,577
  • 1
  • 14
  • 21
  • Please show the test code too. – qujck Feb 12 '16 at 18:53
  • @qujck test code added. – Eric G Feb 12 '16 at 19:05
  • is the problem caused by referencing `GlobalConfiguration` and not doing everything in the `config` variable you are creating the `HttpServer` from? – qujck Feb 12 '16 at 20:12
  • Please add the full stack trace. – Steven Feb 12 '16 at 20:43
  • @Steven full stack trace has been added to the Exception section at the top of the question. Also, I wanted you both to be aware that I get the exception at the line `using (HttpResponseMessage response = client.SendAsync(request).Result)` in the controller. – Eric G Feb 12 '16 at 21:25
  • That can't be the complete exception information. This is the stack trace of the inner most exception. Please add the rest. – Steven Feb 12 '16 at 21:56
  • @Steven I have everything that was available in the stack trace. I am viewing this on response.Content.Value. If there is somewhere I should look, please let me know. thanks! – Eric G Feb 12 '16 at 22:19
  • @qujck I tried switching my references over like you suggested and the problem that I was having on my last post came back. My service references all starting to come back null. That's not to say I'm not doing multiple things wrong but I wasn't able to get the services working again with your above mentioned suggestion. – Eric G Feb 12 '16 at 22:24
  • SimpleInjector won't return null which leads me to believe it's not a problem with the container itself – qujck Feb 12 '16 at 23:13
  • The "Make sure that the controller has a parameterless public constructor." will only happen when th official SimplInjectorWebApiDependencyResolver isn't called by Web API. Make sure that this resolver is used when running inside a unit test. – Steven Feb 14 '16 at 02:49
  • @Steven I reordered the code above to hopefully make it easier to see what I'm doing. As you can see I am calling `SimplInjectorWebApiDependencyResolver` in a `TestFixtureSetUp` function I have created using the line `GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);` Am I missing something? – Eric G Feb 15 '16 at 16:13
  • Put a break point in the failing test and take a look at the value of `GlobalConfiguration.Configuration.DependencyResolver`. What value does it have? And does that test still fail with the same error when you hit F5? – Steven Feb 16 '16 at 02:36

1 Answers1

2

The solution for my particular problem was actually to register the dependency resolver on both the in memory HttpServer that I am creating in the tests and on the GlobalConfiguration as well. Above in the question you'll see the creation of the config variable and then this is the code that fixed my issues:

config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); 
GlobalConfiguration.Configuration.DependencyResolver = 
                    new SimpleInjectorWebApiDependencyResolver(container);

Without the config.DependencyResolver I wasn't able to connect to my projects controllers via:

using (HttpResponseMessage response = client.SendAsync(request).Result)

And without GlobalConfiguration.Configuration.DependencyResolver I wasn't able to contact services locally in my test project. Hope this helps someone else!

Eric G
  • 2,577
  • 1
  • 14
  • 21