我正在NUnit Integration Tests
项目中实现.NET Web API 2
控制器REST端点。我们使用Entity Framework
code-first from database
方法来创建我们的控制器和模型。
我已经建立了myProjectIntegrationTests
项目,安装了NUnit
并引用了myProject
。
根据我的研究,下一步是创建一个TestSetup
脚本,该脚本在每次测试时都会在Integration Tests Database
中创建一个LocalDb
。这使我们能够集成测试我们的API调用,而不会影响主dev database
。
此TestSetup
脚本应在每次运行测试时执行几项操作:
-检查Integration Test Db
中当前是否打开了连接-如果是,则将其关闭。
-检查是否存在现有的Integration Test db
-如果存在,请将其拆下。
-运行从我的主dev database
到我的Integration Test Db
的迁移,以向其加载真实数据。
-创建Integration Test Db
的新实例
-运行集成测试...
-关闭Integration Test Db
个连接
-拆解Integration Test Db
创建这个TestSetup
类很麻烦。我找到了有关如何针对.NET MVC,.NET Core以及实体框架执行此操作的教程-但是这些教程似乎都没有利用.Net Web API
,因此所引用的某些库和代码不是为我工作。 有人可以提供示例脚本或教程链接,这些脚本或教程链接可能在.NET Web API 2
中有效吗?
下面是一个使用Entity .Net Core
为EntityFramework进行此操作的示例。这是Michael Perry撰写的关于Entity Framework中集成测试的PluralSight很棒教程的一部分,发现here:
using Globalmantics.DAL;
using Globalmantics.DAL.Migrations;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data.E ntity;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Globalmantics.IntegrationTests
{
[SetUpFixture]
public class TestSetup
{
[OneTimeSetUp]
public void SetUpDatabase()
{
DestroyDatabase();
CreateDatabase();
}
[OneTimeTearDown]
public void TearDownDatabase()
{
DestroyDatabase();
}
private static void CreateDatabase()
{
ExecuteSqlCommand(Master, $@"
CREATE DATABASE [Globalmantics]
ON (NAME = 'Globalmantics',
FILENAME = '{Filename}')");
var migration = new MigrateDatabaseToLatestVersion<
GlobalmanticsContext, GlobalmanticsConfiguration>();
migration.InitializeDatabase(new GlobalmanticsContext());
}
private static void DestroyDatabase()
{
var fileNames = ExecuteSqlQuery(Master, @"
SELECT [physical_name] FROM [sys].[master_files]
WHERE [database_id] = DB_ID('Globalmantics')",
row => (string)row["physical_name"]);
if (fileNames.Any())
{
ExecuteSqlCommand(Master, @"
ALTER DATABASE [Globalmantics] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
EXEC sp_detach_db 'Globalmantics'");
fileNames.ForEach(File.Delete);
}
}
private static void ExecuteSqlCommand(
SqlConnectionStringBuilder connectionStringBuilder,
string commandText)
{
using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = commandText;
command.ExecuteNonQuery();
}
}
}
private static List<T> ExecuteSqlQuery<T>(
SqlConnectionStringBuilder connectionStringBuilder,
string queryText,
Func<SqlDataReader, T> read)
{
var result = new List<T>();
using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = queryText;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
result.Add(read(reader));
}
}
}
}
return result;
}
private static SqlConnectionStringBuilder Master =>
new SqlConnectionStringBuilder
{
DataSource = @"(LocalDB)\MSSQLLocalDB",
InitialCatalog = "master",
IntegratedSecurity = true
};
private static string Filename => Path.Combine(
Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location),
"Globalmantics.mdf");
}
}
这是某人为.Net MVC
做这件事的一个较旧的例子:
using System;
using System.Data.Entity;
using NUnit.Framework;
namespace BankingSite.IntegrationTests
{
[SetUpFixture]
public class TestFixtureLifecycle
{
public TestFixtureLifecycle()
{
EnsureDataDirectoryConnectionStringPlaceholderIsSet();
EnsureNoExistingDatabaseFiles();
}
private static void EnsureDataDirectoryConnectionStringPlaceholderIsSet()
{
// When not running inside MVC application the |DataDirectory| placeholder
// is null in a connection string, e.g AttachDBFilename=|DataDirectory|\TestBankingSiteDb.mdf
AppDomain.CurrentDomain.SetData("DataDirectory", NUnit.Framework.TestContext.CurrentContext.TestDirectory);
}
private void EnsureNoExistingDatabaseFiles()
{
const string connectionString = "name=DefaultConnection";
if (Database.Exists(connectionString))
{
Database.Delete(connectionString);
}
}
}
}
答案 0 :(得分:1)
可能不是您要找的答案,但最近我在docker compose上使用the sql server docker image取得了成功。
当映像关闭时,您可以启动数据库实例并删除数据卷。在docker run命令上使用—rm开关将自动为您完成操作。
如果您使用的是点网核心,则可以设置另一个容器来运行您的实体框架迁移和测试。
如果您使用的是dotnet框架,则也许可以运行Windows泊坞窗映像,但是它们的启动速度会稍慢一些。
如果您从Powershell脚本启动所有内容,则此方法最有效。如您所愿,从代码中启动基础架构可能很棘手,甚至可能比需要的复杂。
答案 1 :(得分:1)
逐行浏览这些操作所需的sql命令类型将很痛苦。仅开发执行拆解/构建步骤的存储过程会更好。您似乎已经有了一个开始,因为我看到您围绕这些语句编写代码。然后,您的集成测试代码将只需要调用此过程并等待设置完成即可。请记住,您不必执行代码中的所有操作。