Moq在测试项目中使用IHttpControllerActivator来使用我的实际CompositionRoot

时间:2016-06-16 16:09:22

标签: c# asp.net-web-api callback moq composition

这主要是一个嘲弄问题。

我正在尝试编写自动Web API测试,并且无法使用外部定义的IHttpControllerActivator在测试环境中激活我的控制器。

我可以激活控制器,如果我模拟IHttpControllerActivator并通过ControllerActivator.Create通过指定它们的具体类型显式连接类型控制器的实例,但这需要我在预定义的合成空间之外双重实现我的合成根:

例如......

var dispatcher = new Moq.Mock<IHttpControllerActivator>();
Type controllerType = typeof(MyController);

repositories.BazingaRepository bazinga = new repositories.BazingaRepository
    (new entities.BazingaEntities());
MyController controller = new MyController(bazinga);

dispatcher.Setup(context => context.Create(
    Moq.It.IsAny<HttpRequestMessage>()
   ,Moq.It.IsAny<HttpControllerDescriptor>()
   ,controllerType)).Returns(controller);
dispatcher.As<IDisposable>().Setup(disposable=>disposable.Dispose());
return dispatcher.Object;

工作,但由于与我的问题没有密切关系的几个原因,这项技术是不受欢迎的。

切入正确的追踪,下面的Root = () =>{...}代码满足构建要求,但无法在运行时激活我的控制器。更具体地说,我无法拨打Create(...)来传递给compositionroot.Create(...)

任何人都可以提供任何有关我的控制器未使用compositionroot.Create(...)激活以及如何解决问题的原因的见解吗?

using my.system.resource.providers;
using Microsoft.Owin.Hosting;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using TechTalk.SpecFlow;
namespace my.system.resource.specs
{
    [Binding]
    public class Steps
    {
        private delegate IHttpControllerActivator Composition();
        private Composition Root;

        [When]
        public void When()
        {
            Root = () =>
            {
                //+=================================================================+
                //|I first tried this out by "just constructing" a                  |
                //|new [my.system.composition.CompositionRoot]                      |
                //|and using it as my dispatcher, since it quite naturally *is*     |
                //|an IHttpControllerActivator, but I could not get any request     |
                //|to hit the Activator at all.  At that point, I thought that it   |
                //|might be possible to build the CompositionRoot, but attach it    |
                //|behind a Mock acting as a proxy for the test (since I know that  |
                //|mocking a Setup of Create(...) actually will work with a Returns)|
                //|So, I am trying to declare that "all of the paramaters to        |
                //|the Dispatcher are Do-Not-Cares. Just pipe them over to          |
                //|compositionroot's Create(...) method.                            |
                //|The code below satisfies all of the build-time requirements,but  |
                //|fails to Activate at run-time.  My error coming out of the system|
                //|is "No HTTP resource was found that matches the request URI"     |
                //+=================================================================+
                var compositionroot = new my.system.composition.CompositionRoot();
                var dispatcher = new Moq.Mock<IHttpControllerActivator>();
                //+=====================================================+
                //|[Edit]                                               |
                //|when I switch It.IsAny<Type> for my                  |
                //|actual controller types in the Setup                 |
                //|below, compositionroot.Create is called              |
                //|but the controller is not returned.                  |
                //+-----------------------------------------------------+
                //|[Alt]Any advice on how I can get the IHttpController |
                //|To be returned as the active controller to my client?|
                //+=====================================================+
                dispatcher.Setup(dispatch =>
                           dispatch.Create(It.IsAny<HttpRequestMessage>()
                                         , It.IsAny<HttpControllerDescriptor>()
                                         , It.IsAny<Type>()))
                                         .Callback((HttpRequestMessage request
                                                  , HttpControllerDescriptor descriptor
                                                  , Type type)
                                                  => compositionroot.Create(request
                                                                          , descriptor
                                                                          , type));

                dispatcher.As<IDisposable>().Setup(disposable => disposable.Dispose());
                return dispatcher.Object;
            };
        }
        [Then]
        public void Then()
        {
            Startup startup = new Startup();

            Hosting.Options options = new Hosting.Options();
            options.Dispatcher = Root();
            startup.Register = () => { return options; };

            using (WebApp.Start(url: "http://localhost:9000", startup: startup.Configuration))
            using (var client = new System.Net.Http.HttpClient())
            {
                Uri resource = new Uri("http://locahost:9000/Resource/Time;now");
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                using (HttpResponseMessage response = client.GetAsync(resource).Result)
                {
                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        var error = response.Content.ReadAsStringAsync().Result;
                        Assert.Fail(error);
                    }
                }
            }
        }
    }
}

my.resource.specs.Startup是:

public class Startup
{

    public delegate MySystemStartupOptions Registration();
    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration configuration = new HttpConfiguration();
        PricingEngineOptions registration = Register();

        configuration.MapHttpAttributeRoutes();
        configuration.EnableCors();
        configuration.Formatters.Clear();
        configuration.Formatters.Add(new XmlMediaTypeFormatter());
        configuration.Formatters.Add(new JsonMediaTypeFormatter());
        configuration.Formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
        configuration.Formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));

              configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new  StringEnumConverter());

        configuration.Services.Replace(typeof(IHttpControllerActivator), registration.Dispatcher);


        app.UseWebApi(configuration);
        return app;
    }

    public Registration Register; 
}
public class MySystemStartupOptions
{
   public IHttpControllerActivator Dispatcher {get;set;}
}

my.system.resource.composition

public partial class CompositionRoot : IHttpControllerActivator
{
   public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
   {
      if(controllerType == typeof(my.system.resource.controllers.TimeController))
      {
         var controller = new my.system.resource.controllers.TimeController();
         return controller;
      }
   }
}

my.system.resource.controllers

public class TimeController : ApiController
{
    [HttpGet]
    [Route("Resource/Time;now")]
    public HttpResponseMessage HttpGetCurrentTime()
    {
       DateTime now = DateTime.Now;
       return Request.CreateResponse(HttpStatusCode.OK, now);
    }
}

编辑以按要求添加包列表和重点项目结构: 涉及4个相关项目

 my.system.resource.specs
 my.system.resource.composition
 my.system.resource.controllers
 my.system.resource.providers

NuGet包

 EntityFramework
  ->my.system.resource.specs|5.0.0
 HtmlAgilityPack
  ->my.system.resource.controllers|1.4.9
 Microsoft.AspNet.Cors
  ->my.system.resource.specs|5.2.3
  ->my.system.resource.controllers|5.2.3
  ->my.system.resource.composition|5.2.3
 Microsoft.AspNet.WebApi
  ->my.system.resource.specs|5.2.3
  ->my.system.resource.composition|5.2.3
 Microsoft.AspNet.WebApi.Cors
  ->my.system.resource.specs|5.2.3
  ->my.system.resource.controllers|5.2.3
  ->my.system.resource.composition|5.2.3
 Microsoft.AspNet.WebApi.Client
  ->my.system.resource.specs|5.2.3
  ->my.system.resource.controllers|5.2.3
  ->my.system.resource.composition|5.2.3
 Microsoft.AspNet.WebApi.Core
  ->my.system.resource.specs|5.2.3
  ->my.system.resource.controllers|5.2.3
  ->my.system.resource.composition|5.2.3
 Microsoft.AspNet.WebApi.Owin
  ->my.system.resource.specs|5.2.3
 Microsoft.AspNet.WebApi.WebHost
  ->my.system.resource.specs|5.2.3
  ->my.system.resource.composition|5.2.3
 Microsoft.AspNet.WebApi.OwinSelfHost
  ->my.system.resource.specs|5.2.3
 Microsoft.Owin.Host.HttpListener
  ->my.system.resource.specs|2.0.2
 Microsoft.Web.Infrastructure 
  ->my.system.resource.specs|1.0.0
 Microsoft.Owin
  ->my.system.resource.specs|2.0.2
 Newtonsoft.Json
  ->my.system.resource.specs|6.0.4
  ->my.system.resource.controllers|6.0.4
  ->my.system.resource.composition|6.0.4
  ->my.system.resource.providers|6.0.4
 Microsoft.Owin.Hosting
  ->my.system.resource.specs|2.0.2
 Owin
  ->my.system.resource.specs|1.0.0 
 Moq
  ->my.system.resource.specs|4.2.1510.22
  ->***my.system.resource.composition|4.2.1510.22 
 SpecFlow
  ->my.system.resource.specs|2.0.0
 SpecFlow.NUnit
  ->my.system.resource.specs|2.0.0
 NUnit
  ->my.system.resource.specs|3.0.0
 StackExchange.Redis
  ->my.system.resource.providers|1.0.488
  ->my.system.resource.controllers|1.0.488

0 个答案:

没有答案