【问题标题】:Owin hosted webapi 2.2. testing controller with mocked serviceOwin 托管的 web api 2.2。使用模拟服务测试控制器
【发布时间】:2015-08-01 00:45:20
【问题描述】:

我有 webapi,出于测试目的,我在 owin 中托管。我已经使用autofac进行了设置。现在,当我测试时,我想注入 moq 依赖项。到目前为止,我无法做到。我已阅读文档并进行了一些研究,但我遗漏了一些东西。

这里是测试代码。

 [Test]
    public void Request_all_airports()
    {
        const int port = 8086;
        AirportCollection moqAirportCollection = new AirportCollection();
        moqAirportCollection.Airports = new List<Airport>{new Airport{IATA = "moq",Name = "moqName"}};

        using (WebApp.Start<Startup>("http://localhost:" + port))
        {
            using (var mock = AutoMock.GetLoose())
            {
                var moqObj =  mock.Mock<IAirportService>().Setup(x => x.GetAirports()).Returns(moqAirportCollection);

                var client = new HttpClient {BaseAddress = new Uri("http://localhost:" + port)};
                var response = client.GetAsync("/api/airport/get").Result;
                var body = response.Content.ReadAsStringAsync().Result;
                var airportCollection = JsonConvert.DeserializeObject<AirportCollection>(body);
            }
        }
    }

请看一看。让我知道我错过了什么。如果您想查看控制器代码或任何其他部分,请告诉我。

这里是启动代码

 public class Startup
{
    public static IContainer container { get; set; }

    public void Configuration(IAppBuilder appBuilder)
    {
        var httpConfig = new HttpConfiguration();
        container = AutofacSetup.Register(httpConfig);
        WebApiConfig.Register(httpConfig);


        appBuilder.UseAutofacMiddleware(container);
        appBuilder.UseAutofacWebApi(httpConfig);
        appBuilder.UseWebApi(httpConfig);
    }
}

谢谢

我想我已经在人们的帮助下解决了这个问题。这是我的代码。

var moq = new Mock<IAirportService>();
                moq.Setup(x => x.GetAirports()).Returns(moqAirportCollection);
                newBuilder.RegisterInstance(moq.Object).As<IAirportService>();
                newBuilder.Update(Startup.container);

我没有重建我刚刚更新的约束。 autofac 具有使用最新注册的行为,因此它将在此处使用 mocked。

【问题讨论】:

  • 在您的应用程序中,您是否在启动时注册了您的依赖项?你能发布你的启动代码和DI设置吗?
  • @AnishPatel 我已经发布了启动代码。在启动时,我正在调用一个自定义类 AutofacSetup.Register,它正在注册所有依赖项。如果你想看看这个,请告诉我。
  • @AnishPatel 请看一看。我已经用可能的解决方案更新了这个问题,它正在工作,请看看,让我知道你的想法。

标签: c# unit-testing asp.net-web-api owin autofac


【解决方案1】:

你快到了。

在您的测试中,您需要将您的模拟服务注册到您的 autofac 容器中,以便通过应用程序中的模拟解决对 IAirportService 的依赖关系。

实现此目的的一种方法是为每个测试覆盖Startup 类的Configuration 方法并将您的测试DI 放入其中。我在下面放了一些 cmets 来显示可以进行的更改:

public class Startup
{
    public static IContainer container { get; set; }

    // make this virtual
    public virtual void Configuration(IAppBuilder appBuilder)
    {
        var httpConfig = new HttpConfiguration();

        // have this return the ContainerBuilder instead of the container
        var builder = AutofacSetup.Register(httpConfig)
        container = builder.Build();

        WebApiConfig.Register(httpConfig);


        appBuilder.UseAutofacMiddleware(container);
        appBuilder.UseAutofacWebApi(httpConfig);
        appBuilder.UseWebApi(httpConfig);
    }
}

然后在您的测试类中,派生自 Startup 类并将您的测试逻辑放入其中。像这样:

public class MyTestCase {
        public static Mock<IAirportService> MockObj { get; set; }

        private class TestStartup : Startup {
            public override void Configuration(IAppBuilder app) {
                var httpConfig = new HttpConfiguration();

                // this now returns ContainerBuilder instead of the container
                var builder = AutofacSetup.Register(httpConfig)

                // register your mock, change this to whatever lifetime scope you need
                var moqAirportCollection = new AirportCollection();
                moqAirportCollection.Airports = new List<Airport>{new Airport{IATA = "moq",Name = "moqName"}};
                var mock = AutoMock.GetLoose()
                MockObj = mock.Mock<IAirportService>()
                                           .Setup(x => x.GetAirports())
                                           .Returns(moqAirportCollection);
                var moqObj = MockObj.Object;
                builder.RegisterInstance(moqObj).As<IAirportService>();



                container = builder.Build();

                WebApiConfig.Register(httpConfig);


                appBuilder.UseAutofacMiddleware(container);
                appBuilder.UseAutofacWebApi(httpConfig);
                appBuilder.UseWebApi(httpConfig);
            }
        }

        [Test]
        public void Request_all_airports()
        {    
           using (var server = WebApp.Start<Startup>())
           {
               var response = 
                   server.CreateRequest("/api/airport/get")
                         .GetAsync()
                         .Result;

                var body = response.Content.ReadAsStringAsync().Result;
                var result = JsonConvert.DeserializeObject<AirportCollection>(body);

                // assert something
            }
        }
    }

【讨论】:

  • 我想我已经接近了。但这条线不起作用“builder.Register(() => moqObj);”错误是关于掩饰表达
  • 抱歉,有些事情不对。我收到此错误。
  • nad 有没有理由这样写 var " moqObj = MockObj = mock......"
  • @haroonlatif 您更新的问题看起来不错,我已经更新了答案以反映这一点。
【解决方案2】:

单元测试应该测试单个组件。在您的情况下,您正在尝试通过 HTTP 查询测试 AirportController,而不是将 AirportController 作为独立组件进行测试。

AirportController 类依赖于 IAirportService 组件。为了在没有任何依赖的情况下测试组件,您在 IAirportService 上创建了一个最小起订量。现在您可以使用此 moq 实例化一个新的 AirportController 并使用此实例运行您的测试。

如果你有这样的AirportController

public class AirportController
{
    public AirportController(IAirportService airportService) { /* ... */}
}

AirportController 测试应该是这样的:

[Test]
public void Request_all_airports()
{
    AirportCollection moqAirportCollection = new AirportCollection();
    var moqAirPort = new Airport{ IATA = "moq",Name = "moqName" };
    moqAirportCollection.Airports = new List<Airport>{ moqAirPort };

    using (var mock = AutoMock.GetLoose())
    {
        var moqAirportService = mock.Mock<IAirportService>()
                                    .Setup(x => x.GetAirports())
                                    .Returns(moqAirportCollection);
        var testedAirportController = new AirportController(moqAirportService); 

        AirportCollection airportCollection = testedAirportController.Get();

        Assert.AreEquals(1, airportCollection.Length, "Invalid number of airport"); 
        Assert.AreEquals(moqAirPort.Name, airportCollection[0].Name, "Invalid name");
    }
}

【讨论】:

    猜你喜欢
    • 2015-04-16
    • 1970-01-01
    • 2019-02-24
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-01
    • 2016-01-25
    相关资源
    最近更新 更多