2016-06-21 12 views
9

Il seguente codice funziona come previsto, ed è molto simile ai campioni presenti sul sito asp:.net nucleo RC2 non funziona

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); 
    } 
} 

Il mio test funziona bene raggiunge l'azione nella controller bene. Tuttavia nella vita reale i test sono un po 'più complicati, ho bisogno di aggiungere alcuni servizi e configurazioni di test personalizzate.

Per fare questo creo un TestStartup che eredita dal mio originale classe progetto di avvio:

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); 
    } 
} 

Come si può vedere solo i delegati al classe base, in modo da ora a cambiare il costruttore di utilizzare il mio Codice 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"); 
    } 

E i test ora non riescono con l'eccezione NotFound Http. Quando si esegue il debug, risulta che l'azione nel controller non viene più colpita dal codice di test.

La mia ipotesi è che in qualche modo mvc non rileva i percorsi se il file di avvio è un assembly diverso dai controller, come posso aggirare questo?

+0

provare a cambiare '_server = new TestServer (hostBulider);' a _server = TestServer.CreateBuilder(). UseStartup (); – Set

+0

Non esiste un metodo statico CreateBuilder sulla classe TestServer, penso che fosse in rc1 – Calin

risposta

1

Ho scritto un post su come eseguire questo tipo di test di integrazione con xUnit qui: http://andrewlock.net/introduction-to-integration-testing-with-xunit-and-testserver-in-asp-net-core.


L'approccio che ho preso è stato quello di creare una classe Fixture che può essere iniettato nella vostra classe di test.

proiettore:

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(); 
    } 
} 

La classe di test quindi implementa 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 
    } 
} 

Per usare MVC, e garantire le vostre opinioni possono essere scoperti, è necessario aggiornare il WebHostBuilder per impostare il percorso contenuto:

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

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

Grazie, ho letto il tuo post sul blog prima di pubblicare la mia domanda in realtà, e dai miei test mostra lo stesso comportamento, farò presto un repository per provarlo. – Calin

0

Cosa versione .net core stai usando? preview1?

Aggiornamento a RTM (anteprima2--31 ...) Forse si è verificato un errore che è già stato risolto.

+0

.net core rc2 è nel titolo della domanda, la versione completa è stata rilasciata. Avrò un test con quello. – Calin

+0

scusate, per me RC2 è preview1: D come SDK –

1

più un ulteriore cambiamento che ho dovuto fare per ottenere una classe di avvio override di lavorare è quello di impostare l'ApplicationName nell'oggetto IHostingEnvironment al nome effettivo del web progetto.

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

Ciò è necessario quando il TestStartup è in un gruppo diverso e sovrascrive la classe di avvio originale. UseContentRoot era ancora richiesto nel mio caso.

Se il nome non è impostato, ho sempre trovato un 404 non trovato.