Как выполнить модульное тестирование запроса Windows Azure Table с заглушкой с помощью Moq? - PullRequest
7 голосов
/ 05 февраля 2012

Я не могу заставить мой модульный тест работать должным образом. Он работает в интеграционном тесте, который у меня есть, где он фактически попадет в хранилище таблиц Azure. Я полагаю, что проблема заключается в макете свойства QueryableEntities , которое повторно запускает Queryable из макета, но возвращает DataServiceQuery из класса ServiceContext. Можно ли создать заглушку типа DataServiceQuery , которая возвращает Queryable?

Это мой код:

Тест

[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();

Ответы [ 2 ]

1 голос
/ 09 февраля 2012

Вы не упомянули ошибку, которую получаете, но, поскольку QueryableEntities является свойством только для чтения, попробуйте использовать mock.SetupGet вместо mock.Setup.

EDIT:

Если посмотреть дальше, проблема заключается в том, что метод расширения .AsTableServiceQuery() пытается привести IQueryable<T> к DataServiceQuery<T>, что не может привести к нулевому исключению.

Есть сообщение Фредерика Бурра о том, как это сделатьмодульное тестирование с хранением таблицы, которое должно вам помочь. Windows Azure Storage: TDD и макеты

0 голосов
/ 02 июля 2013

Я знаю, что вы специально спрашивали, как это сделать, используя Moq, и у меня нет ответа на этот вопрос, но я выяснил, как сделать нечто подобное, используя Fakes.

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

По сути, вы можете создать Shim на 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;
    };
}
...