Azure DevOps 测试数据库

huangapple go评论72阅读模式
英文:

Azure devops test database

问题

目标

我想要一个解决方案,其中包括一个 SQL Server 数据库项目和一个单元测试项目。 (+ 集成测试项目?)

该解决方案将由 Azure DevOps 上的 git 存储库进行源代码控制,理想情况下,我希望有一个流水线,启动 LocalDB (mssqllocaldb) 数据库,运行数据库项目的脚本/datapac,将其升级,然后运行应该能够访问本地服务器上新创建的数据库的单元测试。

我到目前为止的进展

我正在尝试的测试非常简单:(目前使用 dapper,随着我能够让这个测试工作,它将与连接字符串一起移至 API 项目):

[TestMethod]
public void TestDBConnection()
{
    var connString = "Server=(localdb)\\mssqllocaldb;Database=custom_db_name_here;Trusted_Connection=True;";
    using (var connection = new SqlConnection(connString))
    {
        var result = connection.Query<int>(sql: "select 1", commandType: CommandType.Text);
        Assert.AreEqual(result.Count(), 1);
        Assert.AreEqual(result.FirstOrDefault(), 1);
    }
}

我在 DevOps 上没有太多经验,这是 Azure DevOps 生成的 YAML 文件,我添加了 start mssqllocaldb 任务。

trigger:
- master

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: PowerShell@2
  displayName: 'start mssqllocaldb'
  inputs:
    targetType: 'inline'
    script: 'sqllocaldb start mssqllocaldb'

# Publish probably goes here, not sure how though?

- task: VSTest@2
  inputs:
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

问题

我不确定如何创建新的数据库,添加所有结构 (表、存储过程等) 和数据。

英文:

Goal

I would like to have a solution, that among other things includes an SQL Server Database Project and a Unit Test Project. (+ integration test project?)

That solution is going to be source controlled by a git repository on azure devops, and ideally I would like to have a pipeline that starts a LocalDB (mssqllocaldb) database, runs the script/datpac of the database project, to get it up to speed, and then runs the unit tests that should be able to access to newly created database on the local server.

What I've got so far

The test I'm attempting is fairly simple: (currently using dapper, which along with the connection string will be moved to the api project as soon as I can get this test working):

[TestMethod]
public void TestDBConnection()
{
    var connString = &quot;Server=(localdb)\\mssqllocaldb;Database=custom_db_name_here;Trusted_Connection=True;&quot;;
    using (var connection = new SqlConnection(connString))
    {
        var result = connection.Query&lt;int&gt;(sql: &quot;select 1&quot;, commandType: CommandType.Text);
        Assert.AreEqual(result.Count(), 1);
        Assert.AreEqual(result.FirstOrDefault(), 1);
    }
}

I don't have a lot of experience with devops, this is the yaml file azure devops generated and I added the start mssqllocaldb task.

trigger:
- master

pool:
  vmImage: &#39;windows-latest&#39;

variables:
  solution: &#39;**/*.sln&#39;
  buildPlatform: &#39;Any CPU&#39;
  buildConfiguration: &#39;Release&#39;

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: &#39;$(solution)&#39;

- task: VSBuild@1
  inputs:
    solution: &#39;$(solution)&#39;
    msbuildArgs: &#39;/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation=&quot;$(build.artifactStagingDirectory)\WebApp.zip&quot; /p:DeployIisAppPath=&quot;Default Web Site&quot;&#39;
    platform: &#39;$(buildPlatform)&#39;
    configuration: &#39;$(buildConfiguration)&#39;

- task: PowerShell@2
  displayName: &#39;start mssqllocaldb&#39;
  inputs:
    targetType: &#39;inline&#39;
    script: &#39;sqllocaldb start mssqllocaldb&#39;

# Publish probably goes here, not sure how though?

- task: VSTest@2
  inputs:
    platform: &#39;$(buildPlatform)&#39;
    configuration: &#39;$(buildConfiguration)&#39;

Problem

I'm not sure how to create the new database, add all the structures (tables, procedures etc.) and data.

答案1

得分: 2

使用 FluentMigrator(与 dacpac 方法的替代方法)

由于您正在使用 dapper,我建议您使用 FluentMigrator 来管理您的迁移。在长时间运行的环境中,如生产环境中管理迁移时,这将非常有用。

有两种方法可以用来为测试生成数据库并进行种子数据填充。这两个选项实际上只是使用 FluentMigrator 应用迁移的两种方式,内部和外部。

选项 1:作为测试初始化的一部分,内部方式(我个人的首选)

看起来您正在使用 MSTest 框架,所以您可以将运行迁移脚本并填充任何数据的 [AssemblyInitialize] 代码放在这里。由于您为测试填充的数据不打算填充到生产环境中,我建议将其与迁移脚本分开。FluentMigrator 允许您在内部运行迁移(即从您的 C# 代码中运行)。您可以在 FluentMigrator 快速入门指南 中找到详细信息。

使用这种方法,您的流水线将不需要更改。另一个好处是,任何希望为其本地数据库生成架构的开发人员可以在启动其本地数据库后简单运行测试套件。

根据我的经验,尽管我会使用这种方法为测试生成数据库,但我仍然会使用外部方式将迁移应用到长时间运行的环境中。

选项 2:作为流水线中的独立任务,外部方式

这是另一种选项,您可以在 FluentMigrator 快速入门指南 中找到。使用这个选项,您可以在启动 LocalDB 后创建一个任务来运行迁移。我不喜欢这种方法,因为在本地开发时,您必须知道何时通过运行命令来应用迁移,这很繁琐。

使用 SqlPackage(dacpac 方法)

Azure Hosted Agents 默认提供 SqlPackage,一旦构建了您的 .dacpac 文件,请将以下任务添加到您的流水线中,并确保更新生成的 dacpac 文件的路径/名称

- script: SqlPackage /Action:Import /SourceFile:&quot;$(Build.Repository.LocalPath)\dbproject\bin
debug\project.dacpac&quot; /TargetConnectionString:&quot;Data Source=(localdb)\v11.0;Initial Catalog=devdb; Integrated Security=true;&quot;
  workingDirectory: C:\Program Files\Microsoft SQL Server0\DAC\bin\
  displayName: &#39;导入 dacpac&#39;
英文:

Use FluentMigrator (alternative to the dacpac approach)

Since you're using dapper, I would recommend that you use FluentMigrator to manage your migrations. This will come in handy as you manage migrations over time in your long running environments, such as prod.

There are two approaches you could take with to scaffold and seed your database for your tests. These two options are really just the two ways you can apply your migrations with FluentMigrator, in-process and out-of-process.

Option 1: As part of the test initialisation, in-process (My personal preference)

It appears that you're using the MSTest framework, so you would put in your [AssemblyInitialize] code which runs the migration scripts, and seeds any data. Since the data you're seeding for tests is not intended to be seeded into prod, I would keep this separate to the migration scripts. FluentMigrator gives you the ability to run the migrations in-process (i.e. from your C# code). You can find details in the FluentMigrator quickstart guide

Using this approach, your pipeline will not need to change. Another advantage of this is that any developers wanting to scaffold their local db can simply run the test suite after starting their local db.

In my experience, even though I would use this to scaffold the database for tests, I had still used the out-of-process approach for applying the migrations to long running environments.

Option 2: As a separate task in your pipeline, out-of-process

This is another option that you can find in the FluentMigrator quickstart guide. With this option, you'd create a task after starting LocalDB to run the migrations. I don't like this approach because when you're developing locally, you will have to know when to apply migrations by running the command, which is tedious.

Use SqlPackage (dacpac approach)

Azure Hosted Agents provide SqlPackage by default, once you have built your .dacpac file, add the following task to your pipeline, making sure to update the path/name of your produced dacpac

- script: SqlPackage /Action:Import /SourceFile:&quot;$(Build.Repository.LocalPath)\dbproject\bin
debug\project.dacpac&quot; /TargetConnectionString:&quot;Data Source=(localdb)\v11.0;Initial Catalog=devdb; Integrated Security=true;&quot;
  workingDirectory: C:\Program Files\Microsoft SQL Server0\DAC\bin\
  displayName: &#39;Import dacpac&#39;

答案2

得分: 1

我添加了一个构建后事件,将创建的.dacpac复制到解决方案的根目录,以便以后更容易访问它。(还必须将.dacpac添加到.gitignore

  &lt;Target Name=&quot;AfterBuild&quot;&gt;
    &lt;Copy SourceFiles=&quot;$(OutputPath)$(MSBuildProjectName).dacpac&quot; DestinationFolder=&quot;$(SolutionDir)&quot; ContinueOnError=&quot;false&quot; /&gt;
  &lt;/Target&gt;

最终的.yml文件如下:

trigger:
- master

pool:
  vmImage: &#39;windows-latest&#39;

variables:
  solution: &#39;**/*.sln&#39;
  buildPlatform: &#39;Any CPU&#39;
  buildConfiguration: &#39;Release&#39;

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: &#39;$(solution)&#39;

- task: VSBuild@1
  inputs:
    solution: &#39;$(solution)&#39;
    msbuildArgs: &#39;/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation=&quot;$(build.artifactStagingDirectory)\WebApp.zip&quot; /p:DeployIisAppPath=&quot;Default Web Site&quot;&#39;
    platform: &#39;$(buildPlatform)&#39;
    configuration: &#39;$(buildConfiguration)&#39;

- task: PowerShell@2
  displayName: &#39;Start SQL server&#39;
  inputs:
    targetType: &#39;inline&#39;
    script: &#39;sqllocaldb start mssqllocaldb&#39;

- task: PowerShell@2
  displayName: &#39;Deploy DB dacpac&#39;
  inputs:
    targetType: &#39;inline&#39;
    script: &#39;.\SqlPackage.exe /Action:Publish /SourceFile:&quot;$(Build.Repository.LocalPath)$(DBNAME).dacpac&quot; /TargetConnectionString:&quot;Data Source=(localdb)\mssqllocaldb;Initial Catalog=$(DBNAME); Integrated Security=true;&quot;&#39;
    workingDirectory: &#39;C:\Program Files\Microsoft SQL Server0\DAC\bin\&#39;

- task: VSTest@2
  inputs:
    platform: &#39;$(buildPlatform)&#39;
    configuration: &#39;$(buildConfiguration)&#39;

我使用了一个环境变量($(DBNAME))用于数据库和.dacpac文件(它们具有相同的名称,因此我只需为两者创建一个变量)。

如果你想复制此解决方案,唯一需要更改的是环境变量,可能还有.yml文件顶部的触发分支。

英文:

I'm adding this answer just so that the end result I went with is included here. The credit should go to Aaron Zhong and his answer.

I added an after build event that copies the created .dacpac to the root directory of the solution, so that it's easier to access it later. (Also had to add the .dacpac to .gitignore)

  &lt;Target Name=&quot;AfterBuild&quot;&gt;
    &lt;Copy SourceFiles=&quot;$(OutputPath)$(MSBuildProjectName).dacpac&quot; DestinationFolder=&quot;$(SolutionDir)&quot; ContinueOnError=&quot;false&quot; /&gt;
  &lt;/Target&gt;

The final .yml file looks like this:

trigger:
- master

pool:
  vmImage: &#39;windows-latest&#39;

variables:
  solution: &#39;**/*.sln&#39;
  buildPlatform: &#39;Any CPU&#39;
  buildConfiguration: &#39;Release&#39;

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: &#39;$(solution)&#39;

- task: VSBuild@1
  inputs:
    solution: &#39;$(solution)&#39;
    msbuildArgs: &#39;/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation=&quot;$(build.artifactStagingDirectory)\WebApp.zip&quot; /p:DeployIisAppPath=&quot;Default Web Site&quot;&#39;
    platform: &#39;$(buildPlatform)&#39;
    configuration: &#39;$(buildConfiguration)&#39;

- task: PowerShell@2
  displayName: &#39;Start SQL server&#39;
  inputs:
    targetType: &#39;inline&#39;
    script: &#39;sqllocaldb start mssqllocaldb&#39;

- task: PowerShell@2
  displayName: &#39;Deploy DB dacpac&#39;
  inputs:
    targetType: &#39;inline&#39;
    script: &#39;.\SqlPackage.exe /Action:Publish /SourceFile:&quot;$(Build.Repository.LocalPath)$(DBNAME).dacpac&quot; /TargetConnectionString:&quot;Data Source=(localdb)\mssqllocaldb;Initial Catalog=$(DBNAME); Integrated Security=true;&quot;&#39;
    workingDirectory: &#39;C:\Program Files\Microsoft SQL Server0\DAC\bin\&#39;

- task: VSTest@2
  inputs:
    platform: &#39;$(buildPlatform)&#39;
    configuration: &#39;$(buildConfiguration)&#39;

I used an environment variable ($(DBNAME)) for the database and the .dacpac file (they have the same name, so I only had to create 1 variable for both).

If you want to copy this solution the only thing you should have to change is the environment variable and possibly the trigger branch on the top of the .yml file.

I decided not to go with the scaffolding + migration approach, since although it pairs better with git, it feels a lot harder to read and maintain compared to a normal SQL schema.

huangapple
  • 本文由 发表于 2023年5月17日 21:54:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76272901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定