.net核心rc2非平凡集成测试不起作用

时间:2016-06-21 09:19:40

标签: c# asp.net asp.net-core asp.net-core-mvc

以下代码按预期工作,与asp网站上的示例非常相似:

public abstract class BaseResourceTests : IDisposable
{
    private readonly TestServer _server;

    public HttpClient HttpClient { get; }

    protected BaseResourceTests(string resourceVersion)
    {
        var hostBulider = new WebHostBuilder()
            .UseStartup<Startup>();

        _server = new TestServer(hostBulider);

        HttpClient = _server.CreateClient();
        HttpClient.BaseAddress = new Uri("http://localhost:5000");
    }

    public virtual void Dispose()
    {
        HttpClient.Dispose();
        _server.Dispose();
    }
}

public class EndpointTests : BaseResourceTests
{
    public EndpointTests()
        : base(Resource.VersionHeader)
    {
    }

    [Fact]
    public async Task Post_BodyHasValidDto_ReturnsCreated()
    {
        var dto = new Dto { Name = "someDto" };

        var response = await HttpClient.PostAsJsonAsync("/api/someEndpoint", dto);

        Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.Created);
    }
}

我的测试工作正常,它可以很好地到达控制器中的动作。但是在现实生活中,测试稍微复杂一点,我需要添加一些服务和自定义测试配置。

为了做到这一点,我创建了一个继承自原始项目Startup类的TestStartup:

public class TestStartup : Startup
{
    public TestStartup(IHostingEnvironment env) : base(env)
    {
    }

    public override void ConfigureServices(IServiceCollection services)
    {
        base.ConfigureServices(services);
    }

    public override void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        base.Configure(app, env, loggerFactory);
    }
}

正如您所看到的,它只委托给基类,所以现在我更改构建器以使用我的TestStartup代码:

    protected BaseResourceTests(string resourceVersion)
    {
        var hostBulider = new WebHostBuilder()
            .UseStartup<TestStartup>();

        _server = new TestServer(hostBulider);

        HttpClient = _server.CreateClient();
        HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(resourceVersion));
        HttpClient.BaseAddress = new Uri("http://localhost:5000");
    }

现在测试失败了Http NotFound异常。调试时,结果是控制器中的操作不再受测试代码的影响。

我的猜测是,如果启动文件是与控制器不同的程序集,那么mvc不会检测到路由,我该如何解决这个问题?

4 个答案:

答案 0 :(得分:2)

为了让重写的启动类工作,我必须做的另一项更改是将IHostingEnvironment对象中的ApplicationName设置为Web项目的实际名称。

public TestStartup(IHostingEnvironment env) : base(env)
        {
            env.ApplicationName = "Demo.Web";
        }

当TestStartup位于不同的程序集中并覆盖原始的Startup类时,这是必需的。 在我的情况下仍然需要UseContentRoot。

如果没有设置名称,我总是找不到404。

答案 1 :(得分:1)

我写过一篇关于使用xUnit进行此类集成测试的帖子:http://andrewlock.net/introduction-to-integration-testing-with-xunit-and-testserver-in-asp-net-core

我采用的方法是创建一个Fixture类,可以将其注入到测试类中。

夹具:

public class TestFixture<TStartup> : IDisposable where TStartup : class  
{
    private readonly TestServer _server;

    public TestFixture()
    {
        var builder = new WebHostBuilder().UseStartup<TStartup>();
        _server = new TestServer(builder);

        Client = _server.CreateClient();
        Client.BaseAddress = new Uri("http://localhost:5000");
    }

    public HttpClient Client { get; }

    public void Dispose()
    {
        Client.Dispose();
        _server.Dispose();
    }
}

然后测试类实现IClassFixture<TestFixture<TStartup>>

public class MiddlewareIntegrationTests : IClassFixture<TestFixture<SystemUnderTest.Startup>>  
{
    public MiddlewareIntegrationTests(TestFixture<SystemUnderTest.Startup> fixture)
    {
        Client = fixture.Client;
    }

    public HttpClient Client { get; }

    [Fact]
    public async Task AllMethods_RemovesServerHeader(string method)
    {
       // Arrange
       var request = new HttpRequestMessage(new HttpMethod("GET"), "/");

       // Act
       var response = await Client.SendAsync(request);

       //assert etc
    }
}

要使用MVC并确保可以发现您的观看次数,您应该更新WebHostBuilder以设置内容路径:

var path = PlatformServices.Default.Application.ApplicationBasePath;
var setDir = Path.GetFullPath(Path.Combine(path, <projectpathdirectory> ));

var builder = new WebHostBuilder()
    .UseContentRoot(setDir)
    .UseStartup<TStartup>();

答案 2 :(得分:0)

您使用的.net核心版本是什么? preview1?

更新到RTM(预览2--31 ......) 也许你遇到了一个已经修复过的bug。

答案 3 :(得分:0)

您无法通过测试服务覆盖您的服务。我所做的是创建添加依赖项并使方法过度的方法。然后在我的测试中,我将覆盖该方法并注入不同的依赖项。

我也在我的博客中解释了这一点:http://www.stefanhendriks.com/2016/04/29/integration-testing-your-dot-net-core-app-with-an-in-memory-database/