title: Overriding database provider in integration test with WebApplicationFactory
body: <p>I am following the official MS documentation for integration testing .Net Core (<a href="https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.1" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.1</a>). </p>
  
  <p>I was able to get the first part of the integration test done where I was not overriding the startup class of the application I am testing (i.e. I was using a web application factorythat did not override any services). </p>
  
  <p>I want to override the database setup to use an in-memory database for the integration test. The problem I am running into is that the configuration continues to try and use the sql server for <code>services.AddHangfire()</code>. </p>
  
  <p>How do I override only above specific item in my integration test? I only want to override the <code>AddHangfire</code> setup and not <code>services.AddScoped&lt;ISendEmail, SendEmail&gt;().</code> Any help would be appreciated.</p>
  
  <p><strong>Test Class with the custom web application factory</strong></p>
  
  <pre><code> public class HomeControllerShouldCustomFactory : IClassFixture&lt;CustomWebApplicationFactory&lt;Startup&gt;&gt;
      {
          private readonly HttpClient _client;
          private readonly CustomWebApplicationFactory&lt;Startup&gt; _factory;
  
          public HomeControllerShouldCustomFactory(CustomWebApplicationFactory&lt;Startup&gt; factory)
          {
              _factory = factory;
              _client = factory.CreateClient();
          }
  
          [Fact]
          public async Task IndexRendersCorrectTitle()
          {
              var response = await _client.GetAsync("/Home/Index");
  
              response.EnsureSuccessStatusCode();
  
              var responseString = await response.Content.ReadAsStringAsync();
  
              Assert.Contains("Send Email", responseString);
          }
  }
  </code></pre>
  
  <p><strong>Custom Web Application Factory</strong></p>
  
  <pre><code>public class CustomWebApplicationFactory&lt;TStartup&gt;: WebApplicationFactory&lt;SendGridExample.Startup&gt;
      {
          protected override void ConfigureWebHost(IWebHostBuilder builder)
          {
              builder.ConfigureServices(services =&gt;
              {
                  // Create a new service provider.
                  var serviceProvider = new ServiceCollection()
                      .AddEntityFrameworkInMemoryDatabase()
                      .BuildServiceProvider();
  
                  var inMemory = GlobalConfiguration.Configuration.UseMemoryStorage();
                  services.AddHangfire(x =&gt; x.UseStorage(inMemory));
  
                  // Build the service provider.
                  var sp = services.BuildServiceProvider();
  
              });
          }
      }
  </code></pre>
  
  <p><strong>My startup.cs in my application that I am testing</strong></p>
  
  <p>public IConfiguration Configuration { get; }
      public IHostingEnvironment Environment { get; }</p>
  
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      services.AddHangfire(x =&gt; x.UseSqlServerStorage(Configuration.GetConnectionString("ASP_NetPractice")));
      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
      services.AddScoped&lt;ISendEmail, SendEmail&gt;();
  }
  
  
  public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  {
      app.UseHangfireServer();
      app.UseHangfireDashboard();
      RecurringJob.AddOrUpdate&lt;ISendEmail&gt;((email) =&gt; email.SendReminder(), Cron.Daily);
      app.UseMvc();
  </code></pre>
  
  <hr>
  
  <p><strong>Update</strong></p>
  
  <p>I don't see this issue in my other example project where I am using only entity framework. I have a simple application with an application db context which uses SQL server. In my test class, I override it with an in-memory database and everything works. I am at a loss at to why it will work in my example application but not work in my main application. Is this something to do with how HangFire works?</p>
  
  <p>In my test application (example code below), I can delete my sql database, run my test, and the test passes because the application DB context does not go looking for the sql server instance but uses the in-memory database. In my application, the HangFire service keeps trying to use the sql server database (if I delete the database and try to use an in-memory database for the test - it fails because it can't find the instance its trying to connect to). How come there is such a drastic difference in how the two projects work when a similar path is used for both?</p>
  
  <p>I ran through the debugger for my integration test which calls the index method on the home controller above (using the CustomWebApplicationFactory). As I am initializing a test server, it goes through my startup class which calls  below in ConfigureServices: </p>
  
  <pre><code>services.AddHangfire(x =&gt; x.UseSqlServerStorage(Configuration.GetConnectionString("ASP_NetPractice"))); 
  </code></pre>
  
  <p>After that, the Configure method tries to call below statement:</p>
  
  <pre><code>app.UseHangfireServer();
  </code></pre>
  
  <p>At this point the test fails as It cannot find the DB. The DB is hosted on Azure so I am trying to replace it with an in-memory server for some of the integration test. Is the approach I am taking incorrect?</p>
  
  <hr>
  
  <p>My example application where its working</p>
  
  <p><strong>Application DB Context in my example application</strong></p>
  
  <pre><code>public class ApplicationDbContext : DbContext
      {
          public ApplicationDbContext(DbContextOptions&lt;ApplicationDbContext&gt; options)
              : base(options)
          {
          }
  
          public virtual DbSet&lt;Message&gt; Messages { get; set; }
  
          public async  Task&lt;List&lt;Message&gt;&gt; GetMessagesAsync()
          {
              return await Messages
                  .OrderBy(message =&gt; message.Text)
                  .AsNoTracking()
                  .ToListAsync();
          }
  
          public void Initialize()
          {
              Messages.AddRange(GetSeedingMessages());
              SaveChanges();
          }
  
          public static List&lt;Message&gt; GetSeedingMessages()
          {
              return new List&lt;Message&gt;()
              {
                  new Message(){ Text = "You're standing on my scarf." },
                  new Message(){ Text = "Would you like a jelly baby?" },
                  new Message(){ Text = "To the rational mind, nothing is inexplicable; only unexplained." }
              };
          }
      }
  </code></pre>
  
  <p><strong>Startup.cs in my example application</strong></p>
  
  <pre><code>services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;
                  options.UseSqlServer(
                      Configuration.GetConnectionString("DefaultConnection")));
  </code></pre>
  
  <p><strong>CustomWebApplicationFactory - in my unit test project</strong></p>
  
  <pre><code>public class CustomWebApplicationFactory&lt;TStartup&gt;
       : WebApplicationFactory&lt;Startup&gt;
      {
          protected override void ConfigureWebHost(IWebHostBuilder builder)
          {
              builder.ConfigureServices(services =&gt;
              {
                  // Create a new service provider.
                  var serviceProvider = new ServiceCollection()
                      .AddEntityFrameworkInMemoryDatabase()
                      .BuildServiceProvider();
  
                  // Add a database context (ApplicationDbContext) using an in-memory 
                  // database for testing.
                  services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;
                  {
                      options.UseInMemoryDatabase("InMemoryDbForTesting");
                      options.UseInternalServiceProvider(serviceProvider);
                  });
  
                  // Build the service provider.
                  var sp = services.BuildServiceProvider();
  
              });
          }
      }
  </code></pre>
  
  <p><strong>My unit test in my unit test project</strong></p>
  
  <pre><code>public class UnitTest1 : IClassFixture&lt;CustomWebApplicationFactory&lt;Startup&gt;&gt;
      {
          private readonly HttpClient _client;
          private readonly CustomWebApplicationFactory&lt;Startup&gt; _factory;
  
          public UnitTest1(CustomWebApplicationFactory&lt;Startup&gt; factory)
          {
              _factory = factory;
              _client = factory.CreateClient();
          }
  
  
          [Fact]
          public async System.Threading.Tasks.Task Test1Async()
          {
              var response = await _client.GetAsync("/");
  
              //response.EnsureSuccessStatusCode();
  
              var responseString = await response.Content.ReadAsStringAsync();
  
              Assert.Contains("Home", responseString);
          }
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/zfHOh.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zfHOh.jpg" alt="enter image description here"></a></p>
  
  <hr>
  
  <p><strong>Update 2</strong></p>
  
  <p>I think I found an alternate to trying to override all my configuration in my integration test class. Since it's a lot more complicated to override HangFire as opposed to an ApplicationDBContext, I came up with below approach:</p>
  
  <p><strong>Startup.cs</strong></p>
  
  <pre><code>    if (Environment.IsDevelopment())
      {
          var inMemory = GlobalConfiguration.Configuration.UseMemoryStorage();
          services.AddHangfire(x =&gt; x.UseStorage(inMemory));
      }
      else
      {
          services.AddHangfire(x =&gt; x.UseSqlServerStorage(Configuration["DBConnection"]));
  
      }
  </code></pre>
  
  <p>Then in my CustomWebApplicationBuilder, I override the environment type for testing:</p>
  
  <pre><code>public class CustomWebApplicationFactory&lt;TStartup&gt; : WebApplicationFactory&lt;SendGridExample.Startup&gt;
      {
          protected override void ConfigureWebHost(IWebHostBuilder builder)
          {
              builder.UseEnvironment("Development"); //change to Production for alternate test
              builder.ConfigureServices(services =&gt;
              {
                  // Create a new service provider.
                  var serviceProvider = new ServiceCollection()
                      .AddEntityFrameworkInMemoryDatabase()
                      .BuildServiceProvider();
             });
          }
  
      }
  </code></pre>
  
  <p>With that approach, I don't need to worry about having to do extra logic to satisfy hangfire's check for an active DB. It works but I am not 100% convinced its the best approach as I'm introducing branching in my production startup class.</p>