Ho inserito correttamente le dipendenze usando Moq nel mio progetto di test unitario. Ma per il test di integrazione vorrei interagire con il database. Quindi non posso falsificare i repository / dipendenze. Sto avendo problemi su come ottenere questo risultato in una libreria di classi separata introdotta per i test di integrazione.
Mi piacerebbe fare qualcosa del genere (i dati dovrebbero provenire dal database):
public class CountryServiceIntegrationTest
{
private ICountryService countryService;
public CountryServiceIntegrationTest(ICountryService _countryService)
{
countryService = _countryService;
}
#endregion
[Fact]
public void Should_Return_ListOf_Countries()
{
//Act
var myList = countryService.GetList("A");
//Assert
Assert.True(myList.Count > 0);
}
}
My CountryService Class:
public class CountryService : ICountryService
{
// Note: Have to use Core.Domain.Country because of the namespace has Quantum.Service.Country
protected IRepository<Core.Domain.Country> _countryRepository;
protected IRepository<Core.Domain.State> _stateRepository;
protected IRepository<Core.Domain.City> _cityRepository;
public CountryService(IRepository<Core.Domain.Country> countryRepository, IRepository<Core.Domain.State> stateRepository, IRepository<Core.Domain.City> cityRepository)
{
_countryRepository = countryRepository;
_stateRepository = stateRepository;
_cityRepository = cityRepository;
}
public IList<CountryViewModel> GetList(string name)
{
var query = _countryRepository.Table.AsQueryable();
if (string.IsNullOrEmpty(name) == false)
{
query = query.Where(i => i.CountryName.StartsWith(name));
}
return query.Select(i => new CountryViewModel()
{
CountryCode = i.CountryCode,
CountryName = i.CountryName,
Currency = i.Currency,
CurrencyName = i.CurrencyName,
CurrencySymbol = i.CurrencySymbol,
TelephoneCountryCode = i.TelephoneCountryCode,
UnitOfMeasure = i.UnitOfMeasure
}).ToList();
} }
Bene, ho un progetto di libreria di classi IOC separato in cui sono registrate le dipendenze. Questo è quindi registrato nella classe Startup.cs. Poiché la classe Startup.cs non viene richiamata durante i test, le dipendenze non vengono iniettate. Quindi, come posso risolvere questo problema?
------ AGGIORNATO Come da linee guida trovate nella documentazione ufficiale qui -----
Bene ora: ho seguito questo link e fatto come da esso. Mi sembra che sia stata chiamata la classe di avvio che chiama anche ConfigureDependency.RegisterDependencies (..).
Classe di prova:
public CountryServiceIntegrationTest()
{
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnHelloWorld()
{
//Act
var response = await _client.GetAsync("/home/Test");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
//Assert
Assert.Equal("test", responseString);
}
Startup.ConfigureServices ():
public IConfigurationRoot Configuration { get; }
//gets called in the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddSingleton<ILogUserActivityService, LogUserActivityService>();
services.AddSingleton<ActivityLog>();
// Add framework services.
services.AddMvc();
// Register Database Connection String
var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]);
services.AddSingleton<IConnectionSetting>(connectionSetting);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
// Fill other dependencies
var configureDependency = new ConfigureDependency();
configureDependency.RegisterDependencies(services, connectionSetting);
}
ConfigureDependency.RegisterDependency (..):
public class ConfigureDependency
{
public IDatabaseFactory DatabaseFactory { get; set; }
public void RegisterDependencies(IServiceCollection services, IConnectionSetting connectionSetting)
{
services.AddDbContext<QuantumDbContext>(options => options.UseSqlServer(connectionSetting.Get()));
services.AddTransient<IDatabaseFactory, DatabaseFactory>();
services.AddTransient<IDbContext, TestDbContext>();
services.AddTransient<IDbContext, QuantumDbContext>();
..................................................................
...........service n repositories are registered here..............
}
}
Ma ora quello che succede è che ottengo questo errore:
Poiché viene richiamato Startup.cs che quindi chiama la classe ConfigureDependency, non significa che i parametri (services, connectionSetting) devono essere passati automaticamente. Questo è (ConfigureDependency.RegisterDependencies (..)) dove sto ricevendo un errore.
È un ArgumentNullException
nel metodo useSqlServer
:
Sembra che connectionSetting.Get()
restituisca null
.
Nel seguente codice
var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]);
services.AddSingleton<IConnectionSetting>(connectionSetting);
Suggerisce che ConnectionSetting
implementa l'interfaccia IConnectionSetting
quindi perché non hai usato direttamente l'istanza invece di chiamare Get()
su di esso?
Come di seguito:
services.AddDbContext<QuantumDbContext>(options => options.UseSqlServer(connectionSetting))
Note aggiuntive:
Dipende davvero da cosa intendi per test di integrazione . Potrebbe riferirsi a:
Spesso è meglio avere diversi livelli testati prima di provare a fare il test del Big Bang ... ma è una questione di compromesso tra tempo e qualità .
Per rendere possibili / facili da scrivere i test di integrazione di livello più basso:
Non si dovrebbe condividere lo stesso ambiente di database tra i test e il codice di produzione (quindi non la stessa stringa di connessione).
non si dovrebbe utilizzare l'avvio in quanto è progettato per riprodurre l'intero sito Web su un server di prova.
La registrazione e la risoluzione dei servizi dovrebbero essere suddivise in alcune classi coerenti specifiche per facilitare i test di integrazione su parti specifiche.