Je suis ce tutoriel
Test d'intégration avec Entity Framework Core et SQL Server
Mon code ressemble à ceci
Classe de test d'intégration
public class ControllerRequestsShould : IDisposable
{
private readonly TestServer _server;
private readonly HttpClient _client;
private readonly YourContext _context;
public ControllerRequestsShould()
{
// Arrange
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkSqlServer()
.BuildServiceProvider();
var builder = new DbContextOptionsBuilder<YourContext>();
builder.UseSqlServer($"Server=(localdb)\\mssqllocaldb;Database=your_db_{Guid.NewGuid()};Trusted_Connection=True;MultipleActiveResultSets=true")
.UseInternalServiceProvider(serviceProvider);
_context = new YourContext(builder.Options);
_context.Database.Migrate();
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")));
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnListOfObjectDtos()
{
// Arrange database data
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 1, Code = "PTF0001", Name = "Portfolio One" });
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 2, Code = "PTF0002", Name = "Portfolio Two" });
// Act
var response = await _client.GetAsync("/api/route");
response.EnsureSuccessStatusCode();
// Assert
var result = Assert.IsType<OkResult>(response);
}
public void Dispose()
{
_context.Dispose();
}
Si je comprends bien, le .UseStartUp
la méthode garantit que TestServer
utilise ma classe de démarrage
Le problème que j'ai est que lorsque ma déclaration de loi est frappée
var response = await _client.GetAsync("/api/route");
Je reçois une erreur dans ma classe de démarrage que la chaîne de connexion est nulle. Je pense que ma compréhension du problème est que lorsque mon contrôleur est touché par le client, il injecte mon référentiel de données, qui à son tour injecte le contexte db.
Je pense que je dois configurer le service dans le cadre du new WebHostBuilder
section pour qu'il utilise le contexte créé dans le test. Mais je ne sais pas comment faire ça.
Méthode ConfigureServices dans Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services
services.AddMvc(setupAction =>
{
setupAction.ReturnHttpNotAcceptable = true;
setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
});
// Db context configuration
var connectionString = Configuration["ConnectionStrings:YourConnectionString"];
services.AddDbContext<YourContext>(options => options.UseSqlServer(connectionString));
// Register services for dependency injection
services.AddScoped<IYourRepository, YourRepository>();
}
Voici deux options:
WebHostBuilder.ConfigureServices
Utilisation WebHostBuilder.ConfigureServices
ensemble avec WebHostBuilder.UseStartup<T>
pour remplacer et simuler les enregistrements DI d'une application Web:
_server = new TestServer(new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddScoped<IFooService, MockService>();
})
.UseStartup<Startup>()
);
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//use TryAdd to support mocking IFooService
services.TryAddTransient<IFooService, FooService>();
}
}
Le point clé ici est d'utiliser les méthodes TryAdd
à l'intérieur de la classe Startup
d'origine. Douane WebHostBuilder.ConfigureServices
est appelé avant l'original Startup
, les mocks sont donc enregistrés avant les services d'origine. TryAdd
ne fait rien si la même interface a déjà été enregistrée, donc les vrais services ne seront même pas touchés.
Plus d'informations: Exécution de tests d'intégration pour les applications ASP.NET Core .
Créez la classe TestStartup
pour reconfigurer ASP.NET Core DI. Vous pouvez l'hériter de Startup
et remplacer uniquement les méthodes nécessaires:
public class TestStartup : Startup
{
public TestStartup(IHostingEnvironment env) : base(env) { }
public override void ConfigureServices(IServiceCollection services)
{
//mock DbContext and any other dependencies here
}
}
Alternativement, TestStartup
peut être créé à partir de zéro pour garder les tests plus propres.
Et spécifiez-le dans UseStartup
pour exécuter le serveur de test:
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
Ceci est un grand exemple complet: Intégration testant votre application principale asp .net avec une base de données en mémoire .
La réponse de @ ilya-chumakov est impressionnante. Je voudrais juste ajouter une option de plus
. Utilisez la méthode ConfigureTestServices de WebHostBuilderExtensions.
La méthode ConfigureTestServices est disponible dans la version 2.1 de Microsoft.AspNetCore.TestHost (le 20.05.2018, c'est RC1-final). Et cela nous permet de remplacer les enregistrements existants par des simulacres.
Le code:
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureTestServices(services =>
{
services.AddTransient<IFooService, MockService>();
})
);