Integration test always returning 500 Status Code

asp.net-core c# entity-framework-core

Question

I'm building my first system and I'm trying to maintain good practices like testing.

Right now I'm facing a problem with my integration tests setup. I just followed the skeleton from Microsoft with a little change to use SQL Lite InMemory db.

When I run the test I only get a StatusCode 500 - Internal Server Error

I'm pretty sure it is something about my configuration, but I'm looking at it for hours and still couldn't find the problem.

BasicTest.cs

using PMES.HelpDesk.Teste.IntegrationTests.Factory;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Web;
using Xunit;

namespace PMES.HelpDesk.Teste.IntegrationTests.Controllers
{
    public class BasicTests : IClassFixture<HelpDeskFactory<Startup>>
    {
        private readonly HelpDeskFactory<Startup> _factory;

        public BasicTests(HelpDeskFactory<Startup> factory)
        {
            _factory = factory;
        }

        [Theory]
        [InlineData("/api/categoria")]
        public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
        {
            // Arrange
            var client = _factory.CreateClient();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // Act
            var response = await client.GetAsync(url);

            // Assert
            response.EnsureSuccessStatusCode();
            Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString());
        }
    }
}

Factory.cs

using System;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PMES.HelpDesk.Infraestrutura.Context;

namespace PMES.HelpDesk.Teste.IntegrationTests.Factory
{
    public class HelpDeskFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.ConfigureServices(services =>
            {
                // Remove the app's ApplicationDbContext registration.
                var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<SGPM_HELPDESKContext>));

                if (descriptor != null)
                {
                    services.Remove(descriptor);
                }

                // Add ApplicationDbContext using an in-memory database for testing.
                services.AddDbContext<SGPM_HELPDESKContext>(options =>
                {
                    options.UseSqlite("DataSource=:memory:");
                });

                // Build the service provider.
                var sp = services.BuildServiceProvider();

                // Create a scope to obtain a reference to the database
                // context (ApplicationDbContext).
                using (var scope = sp.CreateScope())
                {
                    var scopedServices = scope.ServiceProvider;
                    var db = scopedServices.GetRequiredService<SGPM_HELPDESKContext>();
                    var logger = scopedServices.GetRequiredService<ILogger<HelpDeskFactory<TStartup>>>();

                    // Ensure the database is created.
                    db.Database.EnsureCreated();

                    try
                    {
                        // Seed the database with test data.
                        //Utilities.InitializeDbForTests(db);
                    }
                    catch (Exception ex)
                    {
                        logger.LogError(ex, "An error occurred seeding the " + "database with test messages. Error: {Message}", ex.Message);
                    }
                }
            });
        }
    }
}

UPDATE 1

I'm getting an exception which is Message "SQLite Error 1: 'no such table: [table]'." string. I tried to update the factory using db.Database.Migrate(); after db.Database.EnsureCreated(); but still didn't work.

1
0
3/10/2020 1:38:23 PM

Accepted Answer

That is because every time a database context is created, a fresh new sqlite memory database is created and there is no table in it.

You configure the database context to be scoped service and let it use a connection string. For each request, a new database context is created and it then creates a new connection according to the connection string and in the connection a fresh new database is created. There is no table in it.

Although you call EnsureCreated for a manually created database context, that is a unique in memory database for that instance which is not shared by other context.

You should create a sqlite connection once and save it for later use.

Create the connection. Remember to dispose it.

var databaseConnection = new SqliteConnection("Data Source=:memory:;");
databaseConnection.Open();

Use the connection to configure database context.

services.AddDbContext<SGPM_HELPDESKContext>(options =>
{
    options.UseSqlite(databaseConnection);
});

You can create connection on demand, for example per test case. Insert the code into proper place.

See docs here.

1
3/13/2020 4:19:45 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow