Estoy tratando de implementar la prueba de integración para poder probar mis puntos finales usando solo HttpClient

public async Task TestEndPoint()
{          
    using (var response = await _client.GetAsync($"/api/car/{id}"))
    {
        //...         
    }
}

Estoy usando la clase Fixture para ayudarme con esto

private readonly TestServer _server;
public Fixture()
{
    var dbContextOptions = new DbContextOptionsBuilder<CarDbContext>()
                    .UseInMemoryDatabase(Guid.NewGuid().ToString())
                    .Options;

    var mockContext = new Mock<CarDbContext>(dbContextOptions);
    var mockOwnerSet = new Mock<DbSet<Owner>>();
    var mockCarSet = new Mock<DbSet<Car>>();
    mockContext.Setup(m => m.Owners).Returns(mockOwnerSet.Object);
    mockContext.Setup(m => m.Cars).Returns(mockCarSet.Object);          

    var carService = new CarService(mockContext.Object);

    _server = new TestServer(new WebHostBuilder()
        .ConfigureAppConfiguration((context, conf) =>
        {
            conf.AddJsonFile(@Directory.GetCurrentDirectory() + "../appsettings.json");
        }).UseStartup<Startup>()
            .ConfigureServices(services =>
            {
                services.AddDbContext<CarDbContext>(options => options.UseInMemoryDatabase("Test"));
                services.AddScoped<ICarService>(_ => carService);
            })
        );

    Client = _server.CreateClient();    
}   

Inside Startup.cs

public class Startup
{
   public void ConfigureServices(IServiceCollection services)
   {
       services.AddDbContext<CarDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("Db")); });
       services.AddTransient<ICarService, CarService>();
   }
}

Clase de servicio

public class CarService: ICarService {
    private readonly CarDbContext _carDbContext;

    public CarService(CarDbContext carDbContext)
    {
        _carDbContext = carDbContext;
    }

    public async Task<Car> GetAsync(int id)
    {
        return await _carDbContext.Cars.FindAsync(id); //this always returns null
    }
}

Mi pregunta es: ¿Por qué no se usa mock dbcontext dentro de Car Service?

return await _carDbContext.Cars.FindAsync (id); siempre devuelve nulo

Actualización:

private readonly TestServer _server;
public TestServer Server;
public Fixture()
{
    _server = new TestServer(new WebHostBuilder()
        .ConfigureAppConfiguration((context, conf) =>
        {
            conf.AddJsonFile(@Directory.GetCurrentDirectory() + "../appsettings.json");
        }).UseStartup<Startup>()
            .ConfigureServices(services =>
            {
                services.AddDbContext<CarDbContext>(options => options.UseInMemoryDatabase(Guid.NewGuid().ToString()));
            })
        );

    Client = _server.CreateClient();    
    Server = _server;
}

// dentro del método de prueba

using (var scope = _server.Host.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<CarDbContext>();
    db.Database.EnsureDeleted();
    Utilities.Seed(db);
}

Y datos de semillas

public static class Utilities
{
    public static void Seed(CarDbContext db)
    {
         db.Cars.Add(new Car("1", "White", "Toyota"));        
         db.SaveChanges(true);
        }
  }

¿Qué estoy haciendo mal exactamente dónde? Todavía obtengo nulo al recuperar datos en

public async Task<Car> GetAsync(int id)
{
    return await _carDbContext.Cars.FindAsync(id); //this always returns null
}
0
user1765862 10 oct. 2019 a las 18:06

1 respuesta

La mejor respuesta

No es necesario burlarse del contexto o de su servicio. Elimine todo antes de la línea _server = new TestServer. En la configuración de su servidor web, ya ha configurado el contexto para usar el proveedor en memoria, por lo que eso es todo lo que es necesario. El contexto se inyectará en el servicio y el servicio se inyectará donde sea necesario. Lo único que está cambiando aquí es la conexión del contexto. En lugar de golpear algo real como una instancia de SQL Server, simplemente almacenará y recuperará de la memoria.

La única otra cosa que debe hacer para su prueba es sembrar la "base de datos" con los datos con los que desea realizar la prueba. En su prueba, deberá acceder a la instancia del servidor de prueba y hacer:

using (var scope = _server.Host.Services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<CarDbContext>();
    context.EnsureDeleted();
    // seed test data
}

// test code
3
Chris Pratt 10 oct. 2019 a las 16:25