单元测试:利用CollectionOrder增加对多数据库同时测试SQLite/SQLServer/MySql

This commit is contained in:
Argo-Surface 2019-01-24 17:58:06 +08:00
parent 79ceedbe8a
commit fc043c8ffc
70 changed files with 660 additions and 49 deletions

View File

@ -9,12 +9,44 @@ using Xunit;
namespace Bootstrap.Admin
{
[CollectionDefinition("BootstrapAdminTestContext")]
[CollectionDefinition("SQLServerContext")]
public class BootstrapAdminTestContext : ICollectionFixture<BAWebHost>
{
}
[CollectionDefinition("SQLiteContext")]
public class SQLiteContext : ICollectionFixture<SQLiteBAWebHost>
{
}
[CollectionDefinition("MySqlContext")]
public class MySqlContext : ICollectionFixture<MySqlBAWebHost>
{
}
public class MySqlBAWebHost : BAWebHost
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
base.ConfigureWebHost(builder);
TestHelper.ConfigureWebHost(builder, Longbow.Data.DatabaseProviderType.MySql);
}
}
public class SQLiteBAWebHost : BAWebHost
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
base.ConfigureWebHost(builder);
TestHelper.ConfigureWebHost(builder, Longbow.Data.DatabaseProviderType.SQLite);
}
}
/// <summary>
///
/// </summary>

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class CategoryTest : Api.CategoryTest
{
public CategoryTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class DictTest : Api.DictTest
{
public DictTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class ExceptionsTest : Api.ExceptionsTest
{
public ExceptionsTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class GroupsTest : Api.GroupsTest
{
public GroupsTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class InterfaceTest : Api.InterfaceTest
{
public InterfaceTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class LoginTest : Api.LoginTest
{
public LoginTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class LogsTest : Api.LogsTest
{
public LogsTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class MenusTest : Api.MenusTest
{
public MenusTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class MessagesTest : Api.MessagesTest
{
public MessagesTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class NewTest : Api.NewTest
{
public NewTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class NotificationsTest : Api.NotificationsTest
{
public NotificationsTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class RegisterTest : Api.RegisterTest
{
public RegisterTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class RolesTest : Api.RolesTest
{
public RolesTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class SettingsTest : Api.SettingsTest
{
public SettingsTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class TasksTest : Api.TasksTest
{
public TasksTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.MySql
{
[Collection("MySqlContext")]
public class UsersTest : Api.UsersTest
{
public UsersTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class CategoryTest : Api.CategoryTest
{
public CategoryTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class DictTest : Api.DictTest
{
public DictTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class ExceptionsTest : Api.ExceptionsTest
{
public ExceptionsTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class GroupsTest : Api.GroupsTest
{
public GroupsTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class InterfaceTest : Api.InterfaceTest
{
public InterfaceTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class LoginTest : Api.LoginTest
{
public LoginTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class LogsTest : Api.LogsTest
{
public LogsTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class MenusTest : Api.MenusTest
{
public MenusTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class MessagesTest : Api.MessagesTest
{
public MessagesTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class NewTest : Api.NewTest
{
public NewTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class NotificationsTest : Api.NotificationsTest
{
public NotificationsTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class RegisterTest : Api.RegisterTest
{
public RegisterTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class RolesTest : Api.RolesTest
{
public RolesTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class SettingsTest : Api.SettingsTest
{
public SettingsTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class TasksTest : Api.TasksTest
{
public TasksTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Api.SQLite
{
[Collection("SQLiteContext")]
public class UsersTest : Api.UsersTest
{
public UsersTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -3,7 +3,7 @@ using Xunit;
namespace Bootstrap.Admin
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class ControllerTest
{
protected HttpClient Client { get; set; }

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Controllers.MySql
{
[Collection("MySqlContext")]
public class AccountTest : Controllers.AccountTest
{
public AccountTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Controllers.MySql
{
[Collection("MySqlContext")]
public class AdminTest : Controllers.AdminTest
{
public AdminTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Controllers.MySql
{
[Collection("MySqlContext")]
public class HomeTest : Controllers.HomeTest
{
public HomeTest(MySqlBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Controllers.SQLite
{
[Collection("SQLiteContext")]
public class AccountTest : Controllers.AccountTest
{
public AccountTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Controllers.SQLite
{
[Collection("SQLiteContext")]
public class AdminTest : Controllers.AdminTest
{
public AdminTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.Admin.Controllers.SQLite
{
[Collection("SQLiteContext")]
public class HomeTest : Controllers.HomeTest
{
public HomeTest(SQLiteBAWebHost factory) : base(factory) { }
}
}

View File

@ -3,7 +3,7 @@ using Xunit;
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class DictsTest
{
[Fact]

View File

@ -4,7 +4,7 @@ using Xunit;
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class ExceptionsTest
{
[Fact]

View File

@ -3,7 +3,7 @@ using Xunit;
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class GroupsTest
{
[Fact]

View File

@ -2,7 +2,7 @@
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class LogsTest
{
[Fact]

View File

@ -3,7 +3,7 @@ using Xunit;
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class MenusTest
{
[Fact]

View File

@ -2,7 +2,7 @@
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class MessagesTest
{
[Fact]

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class DictsTest : DataAccess.DictsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class ExceptionsTest : DataAccess.ExceptionsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class GroupsTest : DataAccess.GroupsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class LogsTest : DataAccess.LogsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class MenusTest : DataAccess.MenusTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class MessagesTest : DataAccess.MessagesTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class RolesTest : DataAccess.RolesTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class TasksTest : DataAccess.TasksTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.MySql
{
[Collection("MySqlContext")]
public class UsersTest : DataAccess.UsersTest
{
}
}

View File

@ -3,7 +3,7 @@ using Xunit;
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class RolesTest
{
[Fact]

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class DictsTest : DataAccess.DictsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class ExceptionsTest : DataAccess.ExceptionsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class GroupsTest : DataAccess.GroupsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class LogsTest : DataAccess.LogsTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class MenusTest : DataAccess.MenusTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class MessagesTest : DataAccess.MessagesTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class RolesTest : DataAccess.RolesTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class TasksTest : DataAccess.TasksTest
{
}
}

View File

@ -0,0 +1,10 @@
using Xunit;
namespace Bootstrap.DataAccess.SQLite
{
[Collection("SQLiteContext")]
public class UsersTest : DataAccess.UsersTest
{
}
}

View File

@ -3,7 +3,7 @@ using Xunit;
namespace Bootstrap.DataAccess
{
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class TasksTest
{
[Fact]

View File

@ -7,7 +7,7 @@ namespace Bootstrap.DataAccess
/// <summary>
///
/// </summary>
[Collection("BootstrapAdminTestContext")]
[Collection("SQLServerContext")]
public class UsersTest
{
/// <summary>
@ -28,7 +28,7 @@ namespace Bootstrap.DataAccess
}
[Fact]
public void Retrieves_Ok()
public virtual void Retrieves_Ok()
{
var u = new User();
Assert.NotEmpty(u.Retrieves());

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: TestCollectionOrderer("UnitTest.CollectionOrder.DisplayNameOrderer", "UnitTest")]
namespace UnitTest.CollectionOrder
{
public class DisplayNameOrderer : ITestCollectionOrderer
{
public IEnumerable<ITestCollection> OrderTestCollections(IEnumerable<ITestCollection> testCollections)
{
return testCollections.OrderBy(collection => collection.DisplayName);
}
}
}

View File

@ -1,7 +1,4 @@
//#define SQLite
//#define MySQL
//#define Npgsql
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
@ -41,13 +38,10 @@ namespace UnitTest
var licFile = RetrievePath($"UnitTest{Path.DirectorySeparatorChar}License{Path.DirectorySeparatorChar}Longbow.lic");
var targetFile = Path.Combine(AppContext.BaseDirectory, "Longbow.lic");
if (!File.Exists(targetFile)) File.Copy(licFile, targetFile, true);
#if SQLite
var dbPath = RetrievePath($"UnitTest{Path.DirectorySeparatorChar}DB{Path.DirectorySeparatorChar}UnitTest.db");
var dbFile = Path.Combine(AppContext.BaseDirectory, "UnitTest.db");
if (!File.Exists(dbFile)) File.Copy(dbPath, dbFile);
#endif
if (!File.Exists(targetFile))
{
File.Copy(licFile, targetFile, true);
}
}
private const string SqlConnectionString = "Data Source=.;Initial Catalog=UnitTest;User ID=sa;Password=sa";
@ -55,38 +49,46 @@ namespace UnitTest
private const string MySqlConnectionString = "Server=localhost;Database=UnitTest;Uid=argozhang;Pwd=argo@163.com;SslMode=none;";
private const string NpgSqlConnectionString = "Server=localhost;Database=UnitTest;User ID=argozhang;Password=sa;";
public static void ConfigureWebHost(IWebHostBuilder builder)
public static void ConfigureWebHost(IWebHostBuilder builder, string providerName = Longbow.Data.DatabaseProviderType.SqlServer)
{
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("ConnectionStrings:ba", SqlConnectionString),
new KeyValuePair<string, string>("DB:0:Enabled", "true")
}));
#if SQLite
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("DB:0:Enabled", "false"),
new KeyValuePair<string, string>("DB:1:Enabled", "true"),
new KeyValuePair<string, string>("DB:1:ConnectionStrings:ba", SQLiteConnectionString)
}));
#endif
#if MySQL
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("DB:0:Enabled", "false"),
new KeyValuePair<string, string>("DB:1:Enabled", "false"),
new KeyValuePair<string, string>("DB:2:Enabled", "true"),
new KeyValuePair<string, string>("DB:2:ConnectionStrings:ba", MySqlConnectionString)
}));
#endif
if (providerName == Longbow.Data.DatabaseProviderType.SQLite)
{
var dbPath = RetrievePath($"UnitTest{Path.DirectorySeparatorChar}DB{Path.DirectorySeparatorChar}UnitTest.db");
var dbFile = Path.Combine(AppContext.BaseDirectory, "UnitTest.db");
if (!File.Exists(dbFile)) File.Copy(dbPath, dbFile);
#if Npgsql
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("DB:0:Enabled", "false"),
new KeyValuePair<string, string>("DB:1:Enabled", "false"),
new KeyValuePair<string, string>("DB:2:Enabled", "false"),
new KeyValuePair<string, string>("DB:3:Enabled", "true"),
new KeyValuePair<string, string>("DB:3:ConnectionStrings:ba", NpgSqlConnectionString)
}));
#endif
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("DB:0:Enabled", "false"),
new KeyValuePair<string, string>("DB:1:Enabled", "true"),
new KeyValuePair<string, string>("DB:1:ConnectionStrings:ba", SQLiteConnectionString)
}));
}
if (providerName == Longbow.Data.DatabaseProviderType.MySql)
{
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("DB:0:Enabled", "false"),
new KeyValuePair<string, string>("DB:1:Enabled", "false"),
new KeyValuePair<string, string>("DB:2:Enabled", "true"),
new KeyValuePair<string, string>("DB:2:ConnectionStrings:ba", MySqlConnectionString)
}));
}
if (providerName == Longbow.Data.DatabaseProviderType.Npgsql)
{
builder.ConfigureAppConfiguration(app => app.AddInMemoryCollection(new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("DB:0:Enabled", "false"),
new KeyValuePair<string, string>("DB:1:Enabled", "false"),
new KeyValuePair<string, string>("DB:2:Enabled", "false"),
new KeyValuePair<string, string>("DB:3:Enabled", "true"),
new KeyValuePair<string, string>("DB:3:ConnectionStrings:ba", NpgSqlConnectionString)
}));
}
}
}
}

View File

@ -10,7 +10,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.2.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="MySql.Data" Version="8.0.13" />
<PackageReference Include="MySql.Data" Version="8.0.14" />
<PackageReference Include="Npgsql" Version="4.0.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">