Модульное тестирование неявного оператора 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}}");