Web API上的NUnit集成测试-如何创建/销毁集成测试数据库 [英] NUnit Integration Tests on Web API - how to create/destroy integration test db

查看:85
本文介绍了Web API上的NUnit集成测试-如何创建/销毁集成测试数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在.NET Web API 2项目中实现控制器REST端点的NUnit Integration Tests.我们使用Entity Framework code-first from database方法来创建我们的控制器和模型.

I'm implementing NUnit Integration Tests of our controller REST endpoints in a .NET Web API 2 project. We use an Entity Framework code-first from database approach to create our controllers and models.

我已经设置了myProjectIntegrationTests项目,并安装了NUnit和对myProject的引用.

I've got the myProjectIntegrationTests project set up, with NUnit installed and a reference to myProject.

根据我的研究,下一步是创建一个TestSetup脚本,该脚本在每次测试时都会在LocalDb中创建一个Integration Tests Database.这样一来,我们就可以集成测试我们的API调用,而不会影响主dev database.

From my research, the next step is to create a TestSetup script which, on each test, creates an Integration Tests Database in a LocalDb. This allows us to integration test our API calls without affecting the master dev database.

TestSetup脚本应在每次运行测试时执行几项操作:
-检查当前是否在Integration Test Db中打开了连接-如果是,则将其关闭.
-检查是否存在现有的Integration Test db-如果存在,则将其拆下.
-运行从主服务器dev database到我的Integration Test Db的迁移,以将其与真实数据一起加载.
-创建Integration Test Db
的新实例 -集成测试正在运行...
-关闭Integration Test Db连接
-拆卸Integration Test Db

This TestSetup script should do several things each time a test runs:
- check if a connection is currently open in Integration Test Db - if so, close it.
- check if an existing Integration Test db exists - if so, tear it down.
- run a migration from my master dev database to my Integration Test Db to load it with real data.
- create a new instance of Integration Test Db
- integration tests run...
- close Integration Test Db connections
- teardown Integration Test Db

创建此TestSetup类是给我带来麻烦的原因.我已经找到了有关如何针对.NET MVC,.NET Core以及实体框架执行此操作的教程-但这些似乎都没有利用.Net Web API,因此所引用的某些库和代码不适用于我. 有人可以提供示例脚本或教程链接,该脚本或教程链接可能在.NET Web API 2中可用吗?

Creating this TestSetup class is what's giving me trouble. I've found tutorials on how to do this for .NET MVC, .NET Core and also Entity Framework - but none of these seem to be utilizing just .Net Web API, so some of the libraries and code being referenced isn't working for me. Can someone provide an example script or tutorial link that might work in .NET Web API 2?


以下是我相信使用.Net Core的某人为EntityFramework进行此操作的示例.这是Michael Perry撰写的有关Entity Framework中集成测试的出色PluralSight教程的一部分,该教程

Here's an example of someone doing this for EntityFramework, using I believe .Net Core. This is part of a great PluralSight tutorial on integration testing in Entity Framework by Michael Perry, found 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这样做的一个较旧的示例:

And here's an older example of someone doing this for .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);    
            }           
        }
    }
}

推荐答案

逐行浏览这些操作所需的sql命令类型将很痛苦.仅开发执行拆解/构建步骤的存储过程会更好.您似乎已经有了一个开始,因为我看到您围绕这些语句编写代码.然后,您的集成测试代码将只需要调用此过程并等待设置完成即可.请记住,您不必执行代码中的所有操作.

Going line-by-line through the type of sql commands you'll need for these operations is just going to be painful. You would benefit much better to just develop a stored procedure that does the tear-down/build-up steps. You appear to already have a start in that as I see you writing code around the statements. Then your integration test code would just need to call this procedure and wait for the setup to complete. Remember, You don't have to do everything in code.

这篇关于Web API上的NUnit集成测试-如何创建/销毁集成测试数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆