簡體   English   中英

如何使用 Moq 使用存根對 Windows Azure 表查詢進行單元測試?

[英]How do I unit test Windows Azure Table query with a stub using Moq?

我無法讓我的單元測試正常工作。

它在我有的集成測試中工作,它實際上會影響 Azure 表存儲。

我猜的問題是對QueryableEntities屬性的模擬,它從模擬中返回一個Queryable<Word>但它從 ServiceContext 類中返回一個DataServiceQuery 是否可以創建返回可查詢的DataServiceQuery類型的存根?

這是我的代碼:

測試

[TestMethod]
    public void GetAExistingWordInStorageShouldReturnCorrectWord()
    {

        Word expected = new Word(Dictionaries.Swedish.ToString(), "Word", "Word");

        List<Word> Words = new List<Word>();
        Words.Add(new Word(Dictionaries.Swedish.ToString(), "Word", "Word"));

        IQueryable<Word> WordQueryable = Words.AsQueryable<Word>();
        
        var mock = new Mock<IServiceContext<Word>>();
        mock.Setup(x => x.QueryableEntities).Returns(WordQueryable);

        DictionaryRepository dr = new DictionaryRepository(Models.Dictionaries.Swedish, "testdictionaries");
        dr.Context = mock.Object;

        Word result = dr.GetWord(expected.Text, false);

        Assert.AreEqual(expected, result);
    }

IServiceContect 接口

public interface IServiceContext<TEntity>
{
    IQueryable<TEntity> QueryableEntities {get;}
}

服務上下文類

public class ServiceContext<TEntity> : TableServiceContext, IServiceContext<TEntity> where TEntity : TableServiceEntity
{

    private readonly string tableName;

    public ServiceContext(CloudStorageAccount account, String tableName)
        : base(account.TableEndpoint.ToString(), account.Credentials)
    {
        this.tableName = tableName;
        this.IgnoreResourceNotFoundException = true;
    }

    public IQueryable<TEntity> QueryableEntities
    {
        get
        {
            return CreateQuery<TEntity>(tableName);
        }
    }

}

字典庫

     public class DictionaryRepository : IDictionaryRepository
{
    public Dictionaries Dictionary { get; set; }
    public String TableName;

    public IServiceContext<Word> Context;

    public DictionaryRepository(Dictionaries dictionary)
        : this(dictionary, "dictionaries")
    {
    }

    public DictionaryRepository(Dictionaries dictionary, String tableName)
    {
        Dictionary = dictionary;
        this.TableName = tableName;
        CloudStorageAccount account = CloudStorageAccount.Parse(***);
        Context = new ServiceContext<Word>(account, this.TableName);
    }

    public List<Tile> GetValidTiles()
    {
        throw new NotImplementedException();
    }

    public Type ResolveEntityType(String name)
    {
        return typeof(Word);
    }

    public Word GetWord(string word, Boolean useCache = false)
    {
      
        var q = this.Context.QueryableEntities.Where(x => x.PartitionKey == Dictionary.ToString() && x.RowKey == word).AsTableServiceQuery();

        Word result = q.Execute().SingleOrDefault();

        if (result == null)
            return null;

        return result;

    }} 

我收到以下錯誤

錯誤:

    ArgumentNullException was unhandled by user code
    Value cannot be null.
    Parameter name: query

在 DictionaryRepository 類中的以下行調用.AsTableServiceQuery()時出現錯誤:

var q = this.Context.QueryableEntities.Where(x => x.PartitionKey == Dictionary.ToString() && x.RowKey == word).AsTableServiceQuery();

您沒有提到您遇到的錯誤,但由於QueryableEntities是只讀屬性,請嘗試使用mock.SetupGet而不是mock.Setup

編輯:

進一步研究它的問題是.AsTableServiceQuery()擴展方法嘗試將IQueryable<T>轉換為DataServiceQuery<T> ,該方法失敗導致空異常。

Frederic Boerr 發表了一篇關於如何使用表存儲進行單元測試的帖子,應該可以幫助您解決問題。 Windows Azure 存儲:TDD 和模擬

我知道你特別問了如何使用 Moq 做到這一點,我沒有答案,但我想出了如何使用 Fakes 做類似的事情。

http://azurator.blogspot.com/2013/07/unit-testing-azure-table-storage-queries.html

本質上,您可以在CloudTableQuery<T>上創建一個 Shim,它讀取查詢正在使用的Expression對象,並使用如下代碼將相同的邏輯應用於您的 IEnumerable:

[TestMethod]
public void here_is_my_test()
{
    IEnumerable<MyEntityType> fakeResults = GetFakeResults();

    using (ShimsContext.Create())
    {
        InterceptCloudTableQueryExecute<MyEntityType>(fakeResults);

        DoQuery();

        AssertStuff();
    }
}

public void InterceptCloudTableQueryExecute<T>(IEnumerable<T> result)
{
    var query = result.AsQueryable();

    ShimCloudTableQuery<T>.AllInstances.Execute = (instance) =>
    {
        // Get the expression evaluator.
        MethodCallExpression ex = (MethodCallExpression)instance.Expression;

        // Depending on how I called CreateQuery, sometimes the objects
        // I need are nested one level deep.
        if (ex.Arguments[0] is MethodCallExpression)
        {
            ex = (MethodCallExpression)ex.Arguments[0];
        }

        UnaryExpression ue = ex.Arguments[1] as UnaryExpression;

        // Get the lambda expression
        Expression<Func<T, bool>> le = ue.Operand as Expression<Func<T, bool>>;

        query = query.Where(le);
        return query;
    };
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM