如何在固定装置抛出异常时使集合失败?

How to fail a collection when its fixture throws an Exception?

我目前正在为成熟的 ASP.NET 应用程序编写一套集成测试。 作为应用程序支持服务的一部分,它使用了一个 Azure blob 存储容器,我需要确保它在 运行 测试之前可以访问并且存在。我想添加有效地相当于检查为应用程序配置的 Azure blob 容器(当 CI 中 运行 时在本地模拟器或 Azure 本身)已启动并准备好处理请求由测试套件制作。如果后端不可访问,大量测试将直接失败,并且由于 Azure 库等待多次超时,它们需要几分钟才能失败。

在集合夹具中抛出或断言时,它似乎并没有真正阻止集合中的任何测试运行,夹具异常也没有出现在结果日志中。

如果在实例化过程中任何关联的固定装置抛出,是否有办法阻止测试运行?


我目前的代码如下:

夹具

using Azure.Storage.Blobs;
using Newtonsoft.Json.Linq;
using System.IO;
using Xunit;

namespace product.test.integration
{
    /// <summary>
    /// This fixture ensures the configured azure blob container used by the FileStorage system is accessible.
    /// A concern mostly in local environments where the Azurite emulator may not be running, but also can alert to a misconfigured testing environment.
    /// </summary>
    public class FileStorageFixture
    {
        public FileStorageFixture()
        {
            //get the configuration
            string appdataLocation = Path.Combine(Directory.GetCurrentDirectory(), "testappsettings.json");
            string appdataContent = File.ReadAllText(appdataLocation);
            var json = JObject.Parse(appdataContent);
            string connectionString = json["Settings"]["FileStorage"]["AzureStorageKey"].Value<string>();
            string containerName = json["Settings"]["FileStorage"]["ContainerName"].Value<string>();
            //check if the container exists
            var container = new BlobContainerClient(connectionString, containerName);
            try
            {
                Assert.True(container.Exists()); //this line will throw if a timeout occurs
            } catch
            {
                throw new System.Exception("Configured FileStorage backend is not accessible!");
            }
        }
    }
}

所有测试扩展的基础测试class (IntegrationTest),以及包含它们的集合:

//...
    [CollectionDefinition("Integration Tests", DisableParallelization = true)]
    public class IntegrationTestCollection :
        //...
        ICollectionFixture<FileStorageFixture> { }

    [Collection("Integration Tests")]
    public abstract class IntegrationTest : IClassFixture<WebApplicationFactory<product.api.Startup>>
    {
//...

实现您想要的方法的一种方法是让夹具在初始化不成功时设置一个标志,并在基础测试的构造函数中查询该标志 class。

FileStorageFixture 中添加标志作为 属性

    public bool initOK { get; private set; } = false;

并根据初始化是否成功设置属性

     try
     {
        Assert.True(container.Exists()); //this line will throw if a timeout occurs
        initOK = true;
     } 
     catch
     {
        initOK = false;
     }

如果您将其余代码包含在 try 内的 FileStorageFixture 构造函数中,将会更加可靠,因为任何地方的异常也会导致您的测试失败。

我假设对夹具的引用作为参数提供给 IntegrationTest 的构造函数,因此如果夹具未正确初始化,您应该在那里抛出异常:

    public IntegrationTest(FileStorageFixture fixture) 
    {
        Assert.True(fixture.initOK, "Configured FileStorage backend is not accessible!");

        // ... and do the rest of the constructor stuff
    }

如果没有 IntegrationTest 对象,none 的测试将 运行。