2012-02-05 64 views
5

我無法讓我的單元測試正常工作。 它在一個集成測試中工作,我有它將實際擊中Azure表存儲。 我想這個問題是物業QueryableEntities至極的嘲諷retruns從模擬可查詢的,但它返回從ServiceContext類DataServiceQuery。是否有可能創建一個類型爲的存根DataServiceQuery這個返回一個Queryable?如何使用Moq單元測試Windows Azure表查詢與存根(Stub)?

這是我的代碼:

測試

[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;} 
} 

ServiceContext類

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 unhandeled by user code 
    Value cannot be null. 
    Parameter name: query 

調用.AsTableServiceQuery(當我得到的錯誤)在下面一行中DictionaryRepository類:

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

考慮包裝的微軟的源代碼在你自己的類中實現一個簡化的接口。 – TrueWill 2012-02-09 13:55:50

回答

1

您沒有提到的錯誤你得到,但是由於QueryableEntities是一個只讀屬性,使用mock.SetupGet代替mock.Setup嘗試。

編輯:

尋找到它進一步的問題是,.AsTableServiceQuery()擴展方法試圖施放IQueryable<T>DataServiceQuery<T>,其失敗導致空例外。

Frederic Boerr發表了一篇關於如何使用表格存儲進行單元測試的文章,該文章可以幫助您解決問題。 Windows Azure Storage: TDD and mocks

+0

沒有工作。我更新了我收到的錯誤的問題。 – Frej 2012-02-09 13:03:34

0

我知道你明確地問過如何用Moq做這個,我沒有答案,但我想通過使用Fakes來做類似的事情。

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

從本質上講,你可以創建CloudTableQuery<T>一個墊片,它讀取查詢使用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; 
    }; 
}