Unit testing data layer's stored functions/procedures using OrmLite without an open connection

107 Views Asked by At

I am trying to unit test our DB layer's stored procedures/functions using OrmLite's ScalarAsync(), for example, with the PostgreSQL dialect. (I tried using SqlLite in-memory but it doesn't do stored procedures or functions.)

I found some hints in the unit-tests for OrmLite on GitHub as well as an article which points to them.

Here's what I have:

    [Fact]
    public async Task TestMyMethod_CallsMyStoredProcedure()
    {
        // Arrange
        Mock<IDashboardDbConnectionFactory> mockConnFac = new();

        MockDialectProvider prov = new();
        prov.ExecFilter = new MockStoredProcExecFilter();
        
        OrmLiteConnectionFactory dbFactory =
            new(
                "User ID=asdf;Password=asdf;Host=localhost;Port=5432;Database=asdf;Pooling=true;Connection Lifetime=0;",
                prov, false);

        OrmLiteConfig.ExecFilter = new MockStoredProcExecFilter();
        mockConnFac.Setup(m => m.OpenAsync(It.IsAny<ISecurityContext>()))
            .Returns(async () =>
        {
            OrmLiteConnection asdf = new(dbFactory);
            OrmLiteConfig.ExecFilter = new MockStoredProcExecFilter();
            await asdf.OpenAsync();
            return asdf;
        });
        mockConnFac.Setup(m => m.Open(It.IsAny<ISecurityContext>()))
            .Returns(() =>
            {
                OrmLiteConnection asdf = new(dbFactory);
                OrmLiteConfig.ExecFilter = new MockStoredProcExecFilter();
                asdf.Open();
                return asdf;
            });
        
        // Act
        MyDataLayerCLass target = new(mockConnFac.Object, new NullLoggerFactory());
        bool test1 =
            await target.ExecMyStoredProcAsync(new Mock<ISecurityContext>().Object, Guid.NewGuid());

        // Assert
        Assert.True(test1);
    }

    private class MockDialectProvider : PostgreSqlDialectProvider
    {
        public MockDialectProvider()
        {
            base.ExecFilter = new MockStoredProcExecFilter();
        }
        public new IOrmLiteExecFilter ExecFilter { get; set; } = new MockStoredProcExecFilter();
    }
    
    private class MockStoredProcExecFilter : OrmLiteExecFilter
    {
        public override T Exec<T>(IDbConnection dbConn, Func<IDbCommand, T> filter)
        {
            try
            {
                T val = base.Exec(dbConn, filter);
                if (dbConn.GetLastSql() == "select central_data.my_stored_function(@UserId, @ParentId)")
                    return (T)(object)true;

                return val;
            }
            catch (Exception)
            {
                if (dbConn.GetLastSql() == "select central_data.my_stored_function(@UserId, @ParentId)")
                    return (T)(object)true;
                throw;
            }
        }
        
        public override async Task<T> Exec<T>(IDbConnection dbConn, Func<IDbCommand, Task<T>> filter)
        {
            try
            {
                // This is where the breakpoint hits. Returns false b/c the ids
                // don't match actual records in the DB.
                T val = await base.Exec(dbConn, filter);
                if (dbConn.GetLastSql() == "select central_data.my_stored_function(@UserId, @ParentId)")
                    return (T)(object)true;

                return val;
            }
            catch (Exception)
            {
                string sql = dbConn.GetLastSql();
                if (sql == "select central_data.my_stored_function(@UserId, @ParentId)")
                {
                    return (T)(object)true;
                }
                throw;
            }
        }
    }

The problem is that it requires a valid connection to a valid database. So it's really an integration test when what I want is a unit test. Is there a way to run the dialect provider without an open connection?

0

There are 0 best solutions below