Проверка параметра, переданного в NEST (elasticsearch)

Я использую NEST для выполнения запросов elasticsearch.

    public IReadOnlyCollection<IHit<Recommendation>> GetRecommendations(
        RecommenderQueryFields shoulds,
        RecommenderQueryFields musts, 
        RecommenderQueryFields mustNots)
    {
        var boolQuery = new BoolQuery();
        boolQuery.Should = GetQueryContainers(shoulds);
        boolQuery.Must = GetQueryContainers(musts);
        boolQuery.MustNot = GetQueryContainers(mustNots);

        var response = _elasticClient.Search<Recommendation>(s => s
            .AllTypes().From(0).Size(10)
            .Query(outerQuery => boolQuery));

        return response.Hits;
    }

У меня есть логика в методе GetQueryContainers, которую я хочу проверить. Есть ли способ проверить, что было передано ElasticClient в объекте boolQuery?

Я уже пробовал следующие вещи, используя NUnit и NSubstitute.

    [Test]
    public void Test1()
    {
        // Arrange
        var searchResponse = Substitute.For<ISearchResponse<Recommendation>>();
        searchResponse.Hits.Returns(new List<IHit<Recommendation>>());
        var elasticClient = Substitute.For<IElasticClient>();

        var sut = new Recommender(elasticClient);

        // Act
        sut.GetRecommendations(null, null, null);

        // Assert
        elasticClient
            .Received(1)
            .Search(Arg.Is<Func<SearchDescriptor<Recommendation>, ISearchRequest>>(x => true));
    }

В Arg.Is<[...]>(x => true) я хотел бы заменить константу true для некоторых проверок на boolQuery. Но я не знаю, возможно ли это и как это делается. Или есть другой способ сделать это?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
531
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

TL;DR Использовать производный QueryVisitor. См. Edit2 ниже.

Обнаружил, что на вопрос уже был дан ответ. Это связано не с NEST, а с тестированием лямбда-выражений. Это невозможно: Модульное тестирование C# Moq с делегатом Lambda Expression или Func

Что можно сделать, так это протестировать запрос JSON, который будет отправлен в elasticsearch, но тогда вам нужен фактический ElasticClient: ElasticSearch NEST 5.6.1 Запрос для модульного теста

Что можно сделать, так это поместить логику в собственный метод/класс. Но тогда вы пишете код просто ради тестирования, которое я не люблю. Нравится:

public BoolQuery GetBoolQuery(RecommenderQueryFields shoulds, RecommenderQueryFields musts,
    RecommenderQueryFields mustNots)
{
    var boolQuery = new BoolQuery();
    boolQuery.Should = GetQueryContainers(shoulds);
    boolQuery.Must = GetQueryContainers(musts);
    boolQuery.MustNot = GetQueryContainers(mustNots);
    return boolQuery;
}

Вы выставляете метод public, который вы не собираетесь использовать, только для тестирования. Но затем вы можете утверждать о boolQuery следующим образом:

[Test]
public void GetRecommendations_CallsElasticSearch()
{
    // Arrange
    var elasticClient = Substitute.For<IElasticClient>();
    var sut = new Recommender(elasticClient);

    // Act
    var boolQuery = sut.GetBoolQuery(new RecommenderQueryFields{BlackListedFor = new List<string>{"asdf"}}, null, null);

    // Assert
    Assert.AreEqual(1, boolQuery.Should.Count());
}

В boolQuery.Should есть список QueryContainer, которые нельзя тестировать, потому что он также генерируется с помощью лямбда-выражений. Хотя это лучше, чем ничего, это все же не самый лучший способ протестировать NEST.

Редактировать

@Russ Cam в комментарии упомянул IQueryContainer и QueryVisitor Что у меня есть:

[Test]
public void test()
{
    // Arrange
    var fieldValue = "asdf";
    var elasticClient = Substitute.For<IElasticClient>();
    var sut = new Recommender(elasticClient);

    // Act
    var boolQuery = sut.GetBoolQuery(new RecommenderQueryFields { BlackListedFor = new List<string> { fieldValue } }, null, null);

    // Assert
    IQueryContainer qc = boolQuery.Should.First(); // Cast to IQueryContainer
    Assert.AreEqual(fieldValue, qc.Match.Query); // Assert value

    // Get "field name"
    var queryVisitor = new QueryVisitor();
    var prettyVisitor = new DslPrettyPrintVisitor(new ConnectionSettings(new InMemoryConnection()));
    qc.Accept(queryVisitor);
    qc.Accept(prettyVisitor);
    Assert.AreEqual(0, queryVisitor.Depth);
    Assert.AreEqual(VisitorScope.Query, queryVisitor.Scope);
    Assert.AreEqual("query: match (field: blacklistedfor.keyword)\r\n", prettyVisitor.PrettyPrint);
}

Доступ к значению поля можно получить через IQueryContainer.

Я пробовал QueryVisitor и DslPrettyPrintVisitor. Первый не дает никакой полезной информации. Он имеет 0 глубины и это запрос? Я уже знаю, что. Со вторым я могу указать некоторую дополнительную информацию, такую ​​как имя поля (черный список) и суффикс (ключевое слово). Не идеально, чтобы утверждать о строковом представлении, но лучше, чем ничего.

Редактировать2

@Russ Cam дал мне решение, которым я очень доволен. Он использует производный QueryVisitor:

public class MatchQueryVisitor : QueryVisitor
{
    public string Field { get; private set; }
    public string Value { get; private set; }

    public override void Visit(IMatchQuery query)
    {
        var inferrer = new Inferrer(new ConnectionSettings(new InMemoryConnection()));
        Field = inferrer.Field(query.Field);
        Value = query.Query;
    }
}

[Test]
public void test()
{
    // Arrange
    var fieldValue = "asdf";
    var elasticClient = Substitute.For<IElasticClient>();
    var sut = new Recommender(elasticClient);

    // Act
    var boolQuery = sut.GetBoolQuery(new RecommenderQueryFields { BlackListedFor = new List<string> { fieldValue } }, null,
        null);

    // Assert
    IQueryContainer qc = boolQuery.Should.First();
    var queryVisitor = new MatchQueryVisitor();
    qc.Accept(queryVisitor);
    Assert.AreEqual(fieldValue, queryVisitor.Value);
    Assert.AreEqual("blacklistedfor.keyword", queryVisitor.Field);
}

Таким образом, в MatchQueryVisitor он получает Field и Value, которые затем утверждаются в тестовом методе.

Существует QueryVisitor, который может посетить QueryContainer и проверить, содержит ли он запрос указанного типа. Другой подход, если вы знаете, какие запросы ожидать, заключается в приведении к IQueryContainer и чтении соответствующего свойства запроса.

Russ Cam 15.02.2019 12:47

Очень хорошо. Спасибо, что указали мне на QueryVisitor и IQuerycontainer. Обновил мой ответ.

Simon Lang 18.02.2019 11:43

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

Russ Cam 18.02.2019 12:04

Ты мой герой. Я обновил свой ответ. Теперь я доволен кодом.

Simon Lang 18.02.2019 17:12

@SimonLang, это здорово. Спасибо за подробный ответ. Очень полезно!!!

DanielS 14.11.2019 17:45

Другие вопросы по теме