Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 单元测试Azure表存储的检索表操作_C#_Azure_Unit Testing_Moq_Azure Table Storage - Fatal编程技术网

C# 单元测试Azure表存储的检索表操作

C# 单元测试Azure表存储的检索表操作,c#,azure,unit-testing,moq,azure-table-storage,C#,Azure,Unit Testing,Moq,Azure Table Storage,我有一些代码要进行单元测试。 作为我要测试的方法的一部分,我正在从Azure存储表数据库中检索一些数据,因此我需要模拟从数据库返回的数据 要测试的代码: public class GetCustomer : IGetCustomer { //constructor public GetCustomer(IClientTableFactory clientTableFactory) { _partitionKey = "test"; _customersT

我有一些代码要进行单元测试。
作为我要测试的方法的一部分,我正在从Azure存储表数据库中检索一些数据,因此我需要模拟从数据库返回的数据

要测试的代码:

public class GetCustomer : IGetCustomer
{
   //constructor
   public GetCustomer(IClientTableFactory clientTableFactory)
   {
      _partitionKey = "test";
      _customersTable = clientTableFactory.GetStorageTable("customers");
   }

   //method to test
   public async Task<string> GetCustomerNameAsync(string email)
   {
      //match on full email
      var match = await SearchAsync(email.ToLower());
      if (match == null)
      {
         //just match on email domain
         var domain = email.ToLower().Substring(email.IndexOf("@"));
         match = await SearchAsync(domain);
      }
      return match;
   }

   //internal method that queries Azure Table Storage
   private async Task<string> SearchAsync(string searchString)
   {
      var query = TableOperation.Retrieve<Customer>(_partitionKey, rowkey: searchString);
      var result = await _customersTable.ExecuteAsync(query);
      var match = result.Result as Customer;
      return match?.Name;
   }
}
//Arrange
var email = "Testy.McTest@Test.com.au";
var tableFactory = new Mock<IClientTableFactory>();
var customersTable = new Mock<CloudTable>(new Uri("http://unittests.localhost.com/FakeTable"));
customersTable.Setup(x => x.ExecuteAsync(It.IsAny<TableOperation>()))
   .ReturnsAsync(new TableResult{ HttpStatusCode = 200, Result = new Customer{ Name = "jiminy crickets" }});
tableFactory.Setup(x => x.GetStorageTable("customers")).Returns(customersTable.Object);
var getCustomers = new GetCustomer(tableFactory.Object);
// Act
var result = await getCustomers.GetCustomerNameAsync(email);
// Assert
Assert.AreEqual("jiminy crickets", result);
公共类GetCustomer:IGetCustomer
{
//建造师
公共GetCustomer(IClientTableFactory客户端TableFactory)
{
_partitionKey=“测试”;
_customersTable=clientTableFactory.GetStorageTable(“客户”);
}
//测试方法
公共异步任务GetCustomerNameAsync(字符串电子邮件)
{
//匹配完整的电子邮件
var match=await SearchAsync(email.ToLower());
if(match==null)
{
//只需匹配电子邮件域
var domain=email.ToLower()子字符串(email.IndexOf(“@”);
匹配=等待搜索异步(域);
}
复赛;
}
//查询Azure表存储的内部方法
专用异步任务SearchAsync(字符串searchString)
{
var query=TableOperation.Retrieve(\u partitionKey,rowkey:searchString);
var result=wait_customersTable.ExecuteAsync(查询);
var匹配=结果。结果为客户;
返回匹配?.Name;
}
}
到目前为止的单元测试:

public class GetCustomer : IGetCustomer
{
   //constructor
   public GetCustomer(IClientTableFactory clientTableFactory)
   {
      _partitionKey = "test";
      _customersTable = clientTableFactory.GetStorageTable("customers");
   }

   //method to test
   public async Task<string> GetCustomerNameAsync(string email)
   {
      //match on full email
      var match = await SearchAsync(email.ToLower());
      if (match == null)
      {
         //just match on email domain
         var domain = email.ToLower().Substring(email.IndexOf("@"));
         match = await SearchAsync(domain);
      }
      return match;
   }

   //internal method that queries Azure Table Storage
   private async Task<string> SearchAsync(string searchString)
   {
      var query = TableOperation.Retrieve<Customer>(_partitionKey, rowkey: searchString);
      var result = await _customersTable.ExecuteAsync(query);
      var match = result.Result as Customer;
      return match?.Name;
   }
}
//Arrange
var email = "Testy.McTest@Test.com.au";
var tableFactory = new Mock<IClientTableFactory>();
var customersTable = new Mock<CloudTable>(new Uri("http://unittests.localhost.com/FakeTable"));
customersTable.Setup(x => x.ExecuteAsync(It.IsAny<TableOperation>()))
   .ReturnsAsync(new TableResult{ HttpStatusCode = 200, Result = new Customer{ Name = "jiminy crickets" }});
tableFactory.Setup(x => x.GetStorageTable("customers")).Returns(customersTable.Object);
var getCustomers = new GetCustomer(tableFactory.Object);
// Act
var result = await getCustomers.GetCustomerNameAsync(email);
// Assert
Assert.AreEqual("jiminy crickets", result);
//排列
var email=“Testy。McTest@Test.com.au";
var tableFactory=newmock();
var customersTable=新模拟(新Uri(“http://unittests.localhost.com/FakeTable"));
customersTable.Setup(x=>x.ExecuteAsync(It.IsAny())
.ReturnsAsync(新的TableResult{HttpStatusCode=200,Result=new Customer{Name=“jiminy crickets”});
tableFactory.Setup(x=>x.GetStorageTable(“客户”)).Returns(customersTable.Object);
var getCustomers=新的GetCustomer(tableFactory.Object);
//表演
var结果=等待getCustomers.GetCustomerNameAsync(电子邮件);
//断言
Assert.AreEqual(“jiminy蟋蟀”,结果);
当然,每次考试都会通过。我想模拟的拼图中缺少的部分是这一行:

customersTable
    .Setup(x => x.ExecuteAsync(It.IsAny<TableOperation>()))
    .ReturnsAsync...
customersTable
.Setup(x=>x.ExecuteAsync(It.IsAny()))
.ReturnsAsync。。。
我应该能够用我的搜索查询替换
It.IsAny()
,例如
It.Is(y=>y.RowKey==”testy。mctest@test.com.au“
但不幸的是,RowKey无法访问

我也试过了

customersTable
    .Setup(x => x.ExecuteAsync(TableOperation.Retrieve<Customer>(_partitionKey, rowkey: searchString))
customersTable
.Setup(x=>x.ExecuteAsync(TableOperation.Retrieve(_partitionKey,rowkey:searchString))
但它在运行时从不传递此代码-可能是因为
ETag
属性


有什么想法吗?我已经看到了很多关于模拟表存储的答案,但是没有看到关于模拟查询结果的答案。

如果您不介意使用反射,您可以在内部成员“RetrievePartitionKey”和“RetrieveRowKey”中找到值

我写了一个简单的方法:

  private T GetInternalMember<T>(object obj, string propertyName)
    {
        Type objType = obj.GetType();
        PropertyInfo propInfo = objType.GetProperty(propertyName,
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        return (T)propInfo.GetValue(obj, null);
    }
private T GetInternalMember(对象对象对象,字符串属性名称)
{
类型objType=obj.GetType();
PropertyInfo-propInfo=objType.GetProperty(propertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
返回(T)propInfo.GetValue(obj,null);
}
我使用它就像:

cloudTable.Verify(x => x.ExecuteAsync(It.Is<TableOperation>(op => GetInternalMember<string>(op, "RetrievePartitionKey") == "TestPartitionKey"
                                                                           && GetInternalMember<string>(op, "RetrieveRowKey") == "TestRowKey")));
cloudTable.Verify(x=>x.ExecuteAsync(It.Is)(op=>GetInternalMember(op,“RetrievePartitionKey”)==“TestPartitionKey”
&&GetInternalMember(op,“RetrieveRowKey”)=“TestRowKey”);

这不是很理想,但它适用于单元测试。

由于
RowKey
在实体中,而不是在操作中,所以在该匹配表达式中尝试执行的操作有点混乱。@nkosi匹配表达式是通过分区键+行键检索单个实体。在我看来,问题似乎是您试图模拟一个static方法。你可以填充它,我在某处有一些代码。我认为这不是一个好主意,你必须将你的项目标记为不安全的,然后交换内存地址。你可以将它按一定的顺序返回结果。TableOperation是静态的吗?如果是的话,可以将它封装在一个类中并注入,这样你可以更容易地模拟它。…表操作类不是,但公共方法是。我完全同意包装,我甚至认为它应该是一个单独的接口和实现,将表存储包装为一个存储库。这感觉超出了范围,但模仿会容易得多。