因此,我正在尝试测试Azure表存储和模拟我所依赖的东西。我的类的结构方式是在构造函数中建立一个连接,即创建一个新的CloudStorageAccount实例,其中我创建了一个具有storageName和storageKey的StorageCredentials实例。之后,我创建了一个CloudTable实例,我在代码中进一步使用它来执行CRUD操作。我的课看起来如下:
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解决方案,比如:
_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.
我的目标是完成这样的任务:
_table.Setup(x => x.DoSomething()).ReturnsAsync("My desired result");任何想法都是非常感谢的!
发布于 2018-12-14 13:43:09
我还在努力实现Azure函数的单元测试,并绑定到Azure表存储。我最终使用了一个派生的CloudTable类来实现它,在这个类中,我可以覆盖我使用的方法并返回固定的结果。
/// <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)实例化模拟类。
var mockTable = new MockCloudTable(new Uri("http://127.0.0.1:10002/devstoreaccount1/screenSettings"));在本例中,'screenSettings‘是表的名称。
现在,模拟类可以从单元测试中传递给Azure函数。
也许这就是你要找的?
发布于 2019-07-24 14:04:42
为了在这里添加答案,由于您的目标是使用一个模拟框架,只需设置一个从CloudTable继承并提供默认构造函数的对象,就可以对继承的对象本身进行伪装,并控制它返回的内容:
public class CloudTableMock : CloudTable
{
public CloudTableMock() : base(new Uri("http://127.0.0.1:10002/devstoreaccount1/screenSettings"))
{
}
}那么这只是一个创建模拟的例子。我正在使用NSubstitute,所以我使用了:
_mockTable = Substitute.For<CloudTableMock>();但我猜莫克会允许:
_mockTableRef = new Mock<CloudTable>();
_mockTableRef.Setup(x => x.DoSomething()).ReturnsAsync("My desired result");
_mockTable = _mockTableRef.Object;(我的Moq有点生疏,所以我猜上面的语法不太正确)
发布于 2021-02-14 01:21:16
我遇到了与选择的答案相同的场景,这个答案涉及带有表绑定的Azure函数。使用模拟CloudTable有一些限制,特别是当使用System.Linq和CreateQuery<T>时,例如,这些是IQueryable上的扩展方法。
一种更好的方法是使用HttpMessageHandler模拟,如RichardSzalay.MockHttp和TableClientConfiguration.RestExecutorConfiguration.DelegatingHandler,然后只需要从表中筛选出您期望的json响应。
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; }
}https://stackoverflow.com/questions/53510000
复制相似问题