ASP.NET Core中用于集成测试的AppSettings.json

28

我正在按照这个指南进行操作。在API项目中,我有一个Startup使用了appsettings.json配置文件。

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)                
            .AddEnvironmentVariables();
        Configuration = builder.Build();

        Log.Logger = new LoggerConfiguration()
            .Enrich.FromLogContext()
            .ReadFrom.Configuration(Configuration)
            .CreateLogger();
    }

我关注的特定部分是 env.ContentRootPath。我进行了一些调查,发现我的 appsettings.json 实际上没有复制到 bin 文件夹中,但这没关系,因为 ContentRootPath 返回的是 MySolution\src\MyProject.Api\,这就是 appsettings.json 文件所在的位置。

因此,在我的集成测试项目中,我有以下测试:

public class TestShould
{
    private readonly TestServer _server;
    private readonly HttpClient _client;

    public TestShould()
    {
        _server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
        _client = _server.CreateClient();
    }

    [Fact]
    public async Task ReturnSuccessful()
    {
        var response = await _client.GetAsync("/monitoring/test");
        response.EnsureSuccessStatusCode();

        var responseString = await response.Content.ReadAsStringAsync();

        Assert.Equal("Successful", responseString);
    }

这基本上是从指南中复制和粘贴的。当我调试这个测试时,ContentRootPath实际上是MySolution\src\MyProject.IntegrationTests\bin\Debug\net461\,这显然是测试项目的生成输出文件夹,而且appsettings.json文件也不在那里(是的,我确实在测试项目本身中有另一个appsettings.json文件),因此测试失败了。

我试图通过修改测试的project.json文件来解决这个问题。

"buildOptions": {
    "emitEntryPoint": true,
    "copyToOutput": {
        "includeFiles": [
            "appsettings.json"
       ]
    }
}

我希望这个操作可以将 appsettings.json 文件复制到生成的输出目录,但是它抱怨该项目缺少一个用于入口点的 Main 方法,将测试项目视为控制台项目。

我应该如何解决这个问题?我做错了什么吗?

3个回答

21

ASP.NET Core 2.0上的集成测试遵循微软指南

你应该右键点击appsettings.json,设置它的属性Copy to Output directoryCopy always

现在,你可以在输出文件夹中找到json文件,并使用它来构建TestServer

var projectDir = GetProjectPath("", typeof(TStartup).GetTypeInfo().Assembly);
_server = new TestServer(new WebHostBuilder()
    .UseEnvironment("Development")
    .UseContentRoot(projectDir)
    .UseConfiguration(new ConfigurationBuilder()
        .SetBasePath(projectDir)
        .AddJsonFile("appsettings.json")
        .Build()
    )
    .UseStartup<TestStartup>());



/// Ref: https://dev59.com/FlQK5IYBdhLWcg3wQt5t#52136848
/// <summary>
/// Gets the full path to the target project that we wish to test
/// </summary>
/// <param name="projectRelativePath">
/// The parent directory of the target project.
/// e.g. src, samples, test, or test/Websites
/// </param>
/// <param name="startupAssembly">The target project's assembly.</param>
/// <returns>The full path to the target project.</returns>
private static string GetProjectPath(string projectRelativePath, Assembly startupAssembly)
{
    // Get name of the target project which we want to test
    var projectName = startupAssembly.GetName().Name;

    // Get currently executing test project path
    var applicationBasePath = System.AppContext.BaseDirectory;

    // Find the path to the target project
    var directoryInfo = new DirectoryInfo(applicationBasePath);
    do
    {
        directoryInfo = directoryInfo.Parent;

        var projectDirectoryInfo = new DirectoryInfo(Path.Combine(directoryInfo.FullName, projectRelativePath));
        if (projectDirectoryInfo.Exists)
        {
            var projectFileInfo = new FileInfo(Path.Combine(projectDirectoryInfo.FullName, projectName, $"{projectName}.csproj"));
            if (projectFileInfo.Exists)
            {
                return Path.Combine(projectDirectoryInfo.FullName, projectName);
            }
        }
    }
    while (directoryInfo.Parent != null);

    throw new Exception($"Project root could not be located using the application root {applicationBasePath}.");
}

参考: 使用WebHostBuilder的TestServer在ASP.NET Core 2.0上不会读取appsettings.json文件,但在1.1版本中却可以


嗨@John_J,你能帮忙回答这个问题吗?谢谢。https://stackoverflow.com/questions/57318131/net-core-integration-test-run-startup-cs-and-configuration-from-other-program - user11721944
嗨@John_J,ProjectDir是什么?它是实际项目的路径还是实际项目构建工件(例如bin-debug类型文件夹)的路径?请在回答中指明,谢谢-另外,如果您正在进行测试,如何指向原始应用程序启动?GetCurrentDirectory是测试项目的目录,而不是真实项目,对吗? - user11721944
嗨@JeremyWatkins,contentRoot是您的.csproj文件所在的位置。我使用https://dev59.com/FlQK5IYBdhLWcg3wQt5t#52136848中的“GetProjectPath”。 - John Jang
@user11721944,作为方法描述,ProjectDir是“获取我们希望测试的目标项目的完整路径”,而不是测试项目目录。试试看吧 :) - John Jang

9
最终,我按照此指南,具体来说是页面底部的Integration Testing部分进行了操作。这样可以避免复制appsettings.json文件到输出目录中,而是告诉测试项目Web应用程序的实际目录。
至于将appsettings.json复制到输出目录中,我也设法让它工作了。结合dudu的答案,我使用了include而不是includeFiles,因此最终的部分看起来像这样:
"buildOptions": {
    "copyToOutput": {
        "include": "appsettings.json"
    }
}

我不确切地知道为什么这个方法可行,但它确实有效。我快速查看了文档,但没有找到任何真正的区别,并且原始问题基本上已经解决,所以我没有深入研究。

据我理解:在测试期间,当您将目标应用程序根目录用作内容根目录和/或基本路径(而不是测试输出目录)时,您的应用程序“启动”将使用其自己的“appsettings.json”,就像在测试之外运行一样。在这种情况下,将测试项目的“appsettings.json”复制到其输出目录将没有任何效果。该json文件将根本不会被读取。这是您的经验吗? - superjos
3
如何在.NET Core 2.0中实现这个?因为project.json已经被废弃了。 - John Jang
嗨 @Kevin Lee,能否具体说明你使用的代码,而不是只指向指南?因为微软在过去两年中有时会更改文档,谢谢。 - user11721944

1

在测试的project.json文件中删除"emitEntryPoint": true


这解决了有关缺少主函数的错误,但它并没有将“appsettings.json”复制到“bin”目录中。 - Kevin Lee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接