Модульное тестирование неявного оператора rubbersearch.net с использованием Moq

Я не уверен, что низкоуровневый клиент ElasticSearch.net все еще широко используется, потому что NEST является подходом для реализации клиента Elasticsearch в.net.

Во всяком случае, среди многих других методов, основной IElasticLowLevelClient Интерфейс предоставляет метод для создания индексов:

ElasticsearchResponse<T> IndicesCreate<T>(
    string index, 
    PostData<object> body, 
    Func<CreateIndexRequestParameters, CreateIndexRequestParameters> requestParameters = null
) where T : class;

Как объясняется в этом документе, вы можете передать строку вместо экземпляра PostData<object> благодаря одному из подручных PostDataнеявные операторы:

public class PostData<T> : IPostData<T>, IPostData
{ 
     // ... code omitted
     public static implicit operator PostData<T>(string literalString);
}

Я тестирую PersonIndexer класс, роль которого призвать IndicesCreate с правильным индексным именем "people" и правильным телом json - мне наплевать на последний параметр. Для этого я издеваюсь IElasticLowLevelClient используя библиотеку Moq.

Вот как PersonIndexer вызывает низкоуровневый клиент для создания индекса:

var result = _elasticClient.IndicesCreate<object>("people", "{ properties: {etc}}", null);

Вот что PersonIndexerTest проверка класса в идеале должна выглядеть так (упрощенный анализ json):

_elasticClientMock.Verify(c => c.IndicesCreate<object>(
            "people",
            It.Is<string>(body =>
                JObject.Parse(body).SelectToken("$.properties.name.type").ToString() == "string"
            ), 
            null
        ));

Проблема в том, что Moq никогда не видит этот вызов, потому что он ожидает PostData<object> соответствовать второму типу аргумента, а не строке.

Вы сказали бы мне использовать "настоящий" базовый тип в моем предложении: It.Is<PostData<object>>(...) но это поднимает другую проблему: PostData Класс публично не раскрывает строку, которую я использовал как неявный конструктор, поэтому он не позволяет мне анализировать тело моего запроса на создание индекса.

Есть ли какой-нибудь трюк, который я могу использовать, чтобы проверить переданную строку? Есть ли способ настроить макет так, чтобы он воспроизводил поведение неявного оператора? Я иду в неправильном направлении...?

1 ответ

Решение

При условии, что вы не тестируете реализацию IElasticLowLevelClient самый простой подход к этой проблеме - определить собственный интерфейс для создания индекса, который будет принимать имя индекса и string тело. Используйте этот интерфейс из своего кода и подтвердите правильность теста.

В качестве альтернативы вы можете использовать немного размышлений, чтобы получить личное _literalString поле в It.Is<PostData<object>>(...) заявление.

ОБНОВИТЬ:

После расследования реализации PostData Я думаю, что нашел лучшее предупреждение для размышлений. Вы можете настроить обратный вызов для вызова метода и записи PostData в поток. Тогда вы сможете конвертировать поток в строку и утверждать.

// Arrange
PostData<object> data = null;
mock
    .Setup(m => m.IndicesCreate<object>(It.IsAny<string>(), It.IsAny<PostData<object>>(), null))
    .Callback<string, PostData<object>>((s, d) => data = d);

// Act
// You test logic

// Assert
var stream = new MemoryStream();
data.Write(stream, fakeSettings);
var index = Enconding.UTF8.GetString(stream.ToArray());
index.Should().Be("{ properties: {etc}}");
Другие вопросы по тегам