首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模拟用于Azure表存储的CloudStorageAccount和CloudTable

模拟用于Azure表存储的CloudStorageAccount和CloudTable
EN

Stack Overflow用户
提问于 2018-11-27 23:49:26
回答 4查看 13.8K关注 0票数 12

因此,我正在尝试测试Azure表存储和模拟我所依赖的东西。我的类的结构方式是在构造函数中建立一个连接,即创建一个新的CloudStorageAccount实例,其中我创建了一个具有storageNamestorageKeyStorageCredentials实例。之后,我创建了一个CloudTable实例,我在代码中进一步使用它来执行CRUD操作。我的课看起来如下:

代码语言:javascript
复制
public class AzureTableStorageService : ITableStorage
{
        private const string _records = "myTable";
        private CloudStorageAccount _storageAccount;
        private CloudTable _table;

        public AzureTableStorageService()
        {
            _storageAccount = new CloudStorageAccount(new StorageCredentials(
                 ConfigurationManager.azureTableStorageName, ConfigurationManager.azureTableStorageKey), true);
            _table = _storageAccount.CreateCloudTableClient().GetTableReference(_records);
            _table.CreateIfNotExistsAsync();
        }

        //...
        //Other methods here
}

_table在整个类中被重用,目的不同。我的目标是模拟它,但是由于它是虚拟的,并且不实现任何接口,所以我无法提供一个简单的Mock解决方案,比如:

代码语言:javascript
复制
_storageAccount = new Mock<CloudStorageAccount>(new Mock<StorageCredentials>(("dummy", "dummy"), true));
_table  = new Mock<CloudTable>(_storageAccount.Object.CreateCloudTableClient().GetTableReference(_records));

因此,当我试图以这种方式构造我的单元测试时,我得到:Type to mock must be an interface or an abstract or non-sealed class.

我的目标是完成这样的任务:

代码语言:javascript
复制
_table.Setup(x => x.DoSomething()).ReturnsAsync("My desired result");

任何想法都是非常感谢的!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-12-14 13:43:09

我还在努力实现Azure函数的单元测试,并绑定到Azure表存储。我最终使用了一个派生的CloudTable类来实现它,在这个类中,我可以覆盖我使用的方法并返回固定的结果。

代码语言:javascript
复制
/// <summary>
/// Mock class for CloudTable object
/// </summary>
public class MockCloudTable : CloudTable
{

    public MockCloudTable(Uri tableAddress) : base(tableAddress)
    { }

    public MockCloudTable(StorageUri tableAddress, StorageCredentials credentials) : base(tableAddress, credentials)
    { }

    public MockCloudTable(Uri tableAbsoluteUri, StorageCredentials credentials) : base(tableAbsoluteUri, credentials)
    { }

    public async override Task<TableResult> ExecuteAsync(TableOperation operation)
    {
        return await Task.FromResult(new TableResult
        {
            Result = new ScreenSettingEntity() { Settings = "" },
            HttpStatusCode = 200
        });
    }
}

我通过传递存储模拟器用于本地存储的配置字符串(请参阅https://learn.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string)实例化模拟类。

代码语言:javascript
复制
var mockTable = new MockCloudTable(new Uri("http://127.0.0.1:10002/devstoreaccount1/screenSettings"));

在本例中,'screenSettings‘是表的名称。

现在,模拟类可以从单元测试中传递给Azure函数。

也许这就是你要找的?

票数 17
EN

Stack Overflow用户

发布于 2019-07-24 14:04:42

为了在这里添加答案,由于您的目标是使用一个模拟框架,只需设置一个从CloudTable继承并提供默认构造函数的对象,就可以对继承的对象本身进行伪装,并控制它返回的内容:

代码语言:javascript
复制
public class CloudTableMock : CloudTable
{
    public CloudTableMock() : base(new Uri("http://127.0.0.1:10002/devstoreaccount1/screenSettings"))
    {
    }
}

那么这只是一个创建模拟的例子。我正在使用NSubstitute,所以我使用了:

代码语言:javascript
复制
_mockTable = Substitute.For<CloudTableMock>();

但我猜莫克会允许:

代码语言:javascript
复制
_mockTableRef = new Mock<CloudTable>();
_mockTableRef.Setup(x => x.DoSomething()).ReturnsAsync("My desired result");
_mockTable = _mockTableRef.Object;

(我的Moq有点生疏,所以我猜上面的语法不太正确)

票数 1
EN

Stack Overflow用户

发布于 2021-02-14 01:21:16

我遇到了与选择的答案相同的场景,这个答案涉及带有表绑定的Azure函数。使用模拟CloudTable有一些限制,特别是当使用System.LinqCreateQuery<T>时,例如,这些是IQueryable上的扩展方法。

一种更好的方法是使用HttpMessageHandler模拟,如RichardSzalay.MockHttp和TableClientConfiguration.RestExecutorConfiguration.DelegatingHandler,然后只需要从表中筛选出您期望的json响应。

代码语言:javascript
复制
public class Azure_Function_Test_With_Table_Binding
{
    [Fact]
    public void Should_be_able_to_stub_out_a_CloudTable()
    {
        var storageAccount = StorageAccount.NewFromConnectionString("UseDevelopmentStorage=true");
        var client = storageAccount.CreateCloudTableClient();

        var mockedRequest = new MockHttpMessageHandler()
            .When("http://127.0.0.1:10002/devstoreaccount1/pizzas*")
            .Respond("application/json", 
            @"{
                ""value"": [
                    {
                        ""Name"": ""Pepperoni"",
                        ""Price"": 9.99
                    }
                ]
            }");

        client.TableClientConfiguration.RestExecutorConfiguration.DelegatingHandler = new MockedRequestAdapter(mockedRequest);
        var table = client.GetTableReference("pizzas");

        var request = new DefaultHttpContext().Request;
        request.Query = new QueryCollection(new Dictionary<string, StringValues> { { "Pizza", new StringValues("Pepperoni") } });

        var result = PizzaStore.Run(request, table, null);

        Assert.IsType<OkObjectResult>(result);
    }
}

public class MockedRequestAdapter : DelegatingHandler
{
    private readonly MockedRequest _mockedRequest;

    public MockedRequestAdapter(MockedRequest mockedRequest) : base()
    {
        _mockedRequest = mockedRequest;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return await _mockedRequest.SendAsync(new HttpRequestMessage(request.Method, request.RequestUri), cancellationToken);
    }
}

public static class PizzaStore
{
    [FunctionName("PizzaStore")]
    public static IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
        [Table("pizzas", Connection = "AzureWebJobsStorage")] CloudTable cloud,
        ILogger log)
    {
        if (req.Query.TryGetValue("Pizza", out var value))
        {
            var pizza = cloud.CreateQuery<Pizza>().Where(p => p.Name == value.ToString()).SingleOrDefault();

            return new OkObjectResult(new { Pizza = pizza.Name, Price = pizza.Price });
        }

        return new NotFoundResult();
    }
}

public class Pizza : TableEntity
{
    public string Name { get; set; }
    public double Price { get; set; }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53510000

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档