【问题标题】:How to implement Azure table storage to allow for Unit Tests如何实现 Azure 表存储以允许单元测试
【发布时间】:2018-02-13 09:39:21
【问题描述】:

我正在为基于 Azure 表存储的持久性组件实施单元测试。该项目有多个 Table Storage 持久化组件,因此目前这些组件实现了一个抽象的TableStorageBase 类来共享它们之间的公共代码。

假设我们有一个类 FooTableStorageComponent 正在测试中,它从表存储中检索 Foo,如果它已过期(即时间戳超过 7 天),它会创建一个新的 Foo。我想创建一个表存储存根,它总是给FooTableStorageComponent 一个虚拟的Foo 7 天以上。然后我想创建一个单元测试,检查是否因此创建了一个新的Foo。不幸的是,由于抽象的TableStorageBase 类,我不能假装连接到 Azure。

如何重新设计此结构以使其可进行单元测试?我应该如何对我的FooTableStorageComponent 进行单元测试?

抽象 TableStorageBase 类:

public abstract class TableStorageBase
{
    private readonly string tableName;
    protected readonly CloudStorageAccount storageAccount;
    protected TableRequestOptions DefaultTableRequestOptions { get; }
    protected OperationContext DefaultOperationContext { get; }
    public CloudTable Table
    {
        get
        {
            return storageAccount.CreateCloudTableClient().GetTableReference(tableName);
        }
    }

    public TableStorageBase(
        string connectionString,
        string tableName,
        LocationMode consistency)
    {
        this.tableName = tableName;
        storageAccount = CloudStorageAccount.Parse(connectionString);
        ServicePoint tableServicePoint = 
            ServicePointManager.FindServicePoint(storageAccount.TableEndpoint);
        tableServicePoint.UseNagleAlgorithm = false;
        tableServicePoint.ConnectionLimit = 500;
        DefaultTableRequestOptions = new TableRequestOptions()
        {
            PayloadFormat = TablePayloadFormat.JsonNoMetadata,
            MaximumExecutionTime = TimeSpan.FromSeconds(5),
            RetryPolicy = new LinearRetry(TimeSpan.FromMilliseconds(500), 3),
            LocationMode = consistency
        };

        DefaultOperationContext = new OperationContext();
        Table.CreateIfNotExists(DefaultTableRequestOptions, DefaultOperationContext);
    }
}

待测类:

public class FooTableStorageComponent : TableStorageBase, IFooComponent
{
    private const string TableName = "foo";
    private const LocationMode ConsistencyMode = LocationMode.PrimaryOnly;

    public FooTableStorageComponent(string connectionString)
         : base(connectionString, TableName, ConsistencyMode)
    {
    }

    public GetFoo(string partitionKey, string rowKey)
    {
        var retrieveOperation = TableOperation.Retrieve<FooTableEntity>(partitionKey, rowkey)
        var tableEntity = (await Table.ExecuteAsync(
            retrieveOperation, 
            DefaultTableRequestOptions, 
            DefaultOperationContext)).Result as FooTableEntity;
        if (tableEntity != null && tableEntity.Timestamp > DateTime.Now.AddDays(-7))
        {
            return tableEntity.ToEntity();
        }
        else
        {
            var foo = CreateFoo(partitionKey, rowKey)
            var insertOperation = TableOperation.InsertOrMerge(FooTableEntity.From(foo));
            await Table.ExecuteAsync(insertOperation);
            return foo;
        }
    }
}

【问题讨论】:

    标签: c# unit-testing azure mocking azure-table-storage


    【解决方案1】:

    我认为对FooTableStorageComponent 进行单元测试没有多大意义,因为这些方法严重依赖于表操作和表实体。它是一个没有任何业务逻辑的简单存储库,因此集成测试会更合适,因为它依赖于子系统。

    您将为使用IFooComponent 的单元测试提供虚假实现。

    【讨论】:

    • 谢谢马丁。我要测试的业务逻辑示例是表实体的 7 天到期。我不想测试表存储本身。我正在考虑将表存储 I/O 逻辑分离到一些通用访问类中,或者以某种方式拦截表存储的访问以欺骗它。也许我必须接受它不是可单元测试的。
    • 您可以编写一个带有时间戳、对象和工厂函数的函数的服务,并将那里的逻辑外包。然后你可以测试它,但我真的认为你不必这样做。
    • 或者可能只是存储库组件中涵盖该逻辑的公共方法。感觉有点做作,但我想我会去的,谢谢。
    猜你喜欢
    • 2020-11-27
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 2015-05-24
    相关资源
    最近更新 更多