Using Ninject.MockingKernel with Asp.Net Web-API

I created a web API project using Ninject, and I used the detailed description here to get it working with the latest version of the web API. Everything is working fine, but now I'm trying to write some tests.

I use in-memory hosting to run the project for tests, as described here , since I have a DelegatingHandler that does authentication and then sets the property in the request message that is used by all Api controllers.

So, I have a base class for my tests and there is a SetUp method, where I configured HttpServer and a configuration that I took quite a bit from my Ninject working code:

 [SetUp] public void Setup() { bootstrapper = new Bootstrapper(); DynamicModuleUtility.RegisterModule( typeof(OnePerRequestHttpModule)); DynamicModuleUtility.RegisterModule( typeof(NinjectHttpModule)); bootstrapper.Initialize(CreateKernel); var config = new HttpConfiguration(); config.Routes.MapHttpRoute("Login", "api/auth/token", new { controller = "Users", action = "Login" }); config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always; config.DependencyResolver = new NinjectResolver(CreateKernel()); config.MessageHandlers.Add( new AuthenticationHandler(CreateUserManager())); Server = new HttpServer(config); } 

This is how I create MoqMockingKernel :

 private static IKernel CreateKernel() { var kernel = new MoqMockingKernel(); kernel.Bind<Func<IKernel>>() .ToMethod(ctx => () => new Bootstrapper().Kernel); kernel.Bind<IHttpModule>() .To<HttpApplicationInitializationHttpModule>(); RegisterServices(kernel); GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel); return kernel; } 

And this is how I register the objects used:

 private static void RegisterServices(IKernel kernel) { kernel.Bind<IUserManager>().ToMock(); kernel.Bind<UsersController>().ToSelf(); } 

Until I test the controller as such, I want the correct instance to call it, so I bind it to ToSelf. I must admit that I assume this is correct. This is a test example:

 public void UserCannotLogin() { System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(Server); string json = string.Format( "{{ \"Username\": \"{0}\", \"Password\": \"{1}\" }}", "wrong", "wrong"); HttpRequestMessage request = CreateRequest(@"api/auth/token", json, HttpMethod.Get); Action action = () => client.SendAsync(request); using (var response = client.SendAsync(request).Result) { response.StatusCode.Should() .Be(HttpStatusCode.Unauthorized); } } 

Basically, I get error 404. When I debug it, it goes to my DelegatingHandler , but it doesn't go to my controller.

I get the feeling that I basically missed the point here, and maybe I wonโ€™t even be able to do what I'm trying to do, but if someone has suggestions for how to do this, or another way to achieve the same, I all ears.

Update. I think this is because the default behavior of MockingKernel is to provide Mock unless otherwise specified, therefore it returns Mock from IHttpControllerSelector . I set a couple of default ones by default:

 kernel.Bind<IHttpControllerSelector>() .To<DefaultHttpControllerSelector>(); kernel.Bind<IContentNegotiator>() .To<DefaultContentNegotiator>(); 

It still does not work, I think, because there are no formatters. I will try it tomorrow and see if I will get me there.

+4
source share
1 answer

Well, I think I was right when I said that I basically missed the point here, but I will answer this if it helps someone else to avoid the same mistake!

Ninject MockingKernel , I think, first of all about auto-bullying, so when you have many interfaces, it doesnโ€™t matter how they are configured in your test, you can ignore them in your tests and they will be automatically created for you.

In the case of the web API, this is certainly not the case, since you do not want the controller selector class to be ridiculed automatically, otherwise you cannot call your controllers.

So, the solution I came up with is to use the standard Ninject Kernel and then bind my interface to a persistent Mock object:

 kernel.Bind<IUserManager>().ToConstant(CreateUserManager()); private IUserManager CreateUserManager() { Mock<IUserManager> userManager = new Mock<IUserManager>(); // Set up the methods you want mocked return userManager.Object; } 

By doing this, I was able to successfully write tests that use the HttpClient to call the HttpServer in memory, which successfully calls my DelegatingHandler and then ends on my controllers.

+1
source

All Articles