1

I wrote a bunch of queries to elastic search and I wanted to write a unit test for them. using this post moq an elastic connection I was able to preform a general mocking. But When I tried to view the Json which is being generated from my query I didn't manage to get it in any way. I tried to follow this post elsatic query moq, but it is relevant only to older versions of Nest because the method ConnectionStatus and RequestInformation is no longer available for an ISearchResponse object.

My test look as follow:

[TestMethod]
 public void VerifyElasticFuncJson()
{
//Arrange
var elasticService = new Mock<IElasticService>();
var elasticClient = new Mock<IElasticClient>();
var clinet = new ElasticClient();
var searchResponse = new Mock<ISearchResponse<ElasticLog>>();
elasticService.Setup(es => es.GetConnection())
    .Returns(elasticClient.Object);

elasticClient.Setup(ec => ec.Search(It.IsAny<Func<SearchDescriptor<ElasticLog>, 
                          ISearchRequest>>())).
                          Returns(searchResponse.Object);

//Act
var service = new ElasticCusipInfoQuery(elasticService.Object);
var FindFunc = service.MatchCusip("CusipA", HostName.GSMSIMPAPPR01, 
                                        LogType.Serilog);
var con = GetConnection();
var search =  con.Search<ElasticLog>(sd => sd
             .Type(LogType.Serilog)
             .Index("logstash-*")
             .Query(q => q
             .Bool(b => b
                    .Must(FindFunc)
                    )
               )     
             );
 **HERE I want to get the JSON** and assert it look as expected**
}

Is there any other way to achieve what I ask?

mo.
  • 4,165
  • 3
  • 34
  • 45
Green
  • 2,405
  • 3
  • 22
  • 46

1 Answers1

3

The best way to do this would be to use the InMemoryConnection to capture the request bytes and compare this to the expected JSON. This is what the unit tests for NEST do. Something like

private static void Main()
{
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    var connectionSettings = new ConnectionSettings(pool, new InMemoryConnection())
        .DefaultIndex("default")
        .DisableDirectStreaming();

    var client = new ElasticClient(connectionSettings);

    // Act
    var searchResponse = client.Search<Question>(s => s
       .Query(q => (q
         .Match(m => m
               .Field(f => f.Title)
               .Query("Kibana")
         ) || q
         .Match(m => m
               .Field(f => f.Title)
               .Query("Elasticsearch")
               .Boost(2)
         )) && +q
         .Range(t => t
               .Field(f => f.Score)
               .GreaterThan(0)
         )
       )
    );
    
    var actual = searchResponse.RequestJson();

    var expected = new 
    {
        query = new {
            @bool = new {
                must = new object[] {
                    new {
                        @bool = new {
                            should = new object[] {
                                new {
                                    match = new {
                                        title = new {
                                            query = "Kibana"
                                        }
                                    }
                                },
                                new {
                                    match = new {
                                        title = new {
                                            query = "Elasticsearch",
                                            boost = 2d
                                        }
                                    }
                                }
                            },
                        }
                    },
                    new {
                        @bool = new {
                            filter = new [] {
                                new {
                                    range = new {
                                        score = new {
                                            gt = 0d
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    };

    // Assert
    Console.WriteLine(JObject.DeepEquals(JToken.FromObject(expected), JToken.Parse(actual)));
}

public static class Extensions
{
    public static string RequestJson(this IResponse response) =>
        Encoding.UTF8.GetString(response.ApiCall.RequestBodyInBytes);
}

I've used an anonymous type for the expected JSON as it's easier to work with than an escaped JSON string.

One thing to note is that Json.NET's JObject.DeepEquals(...) will return true even when there are repeated object keys in a JSON object (so long as the last key/value matches). It's not likely something you'll encounter if you're only serializing NEST searches though, but something to be aware of.

If you're going to have many tests checking serialization, you'll want to create a single instance of ConnectionSettings and share with all, so that you can take advantage of the internal caches within it and your tests will run quicker than instantiating a new instance in each test.

mo.
  • 4,165
  • 3
  • 34
  • 45
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
  • thanks, I think you also answered the post on Nest 2.x. I don't have the method in `RequestJson()` for an `ISearchResponse` object...Im using Nest 5.6. maybe it had to do with that – Green Jun 12 '18 at 12:17
  • apologies, I meant to add it to answer, it's just an extension method :) Added it now – Russ Cam Jun 12 '18 at 12:21
  • No worries, happy to help :) – Russ Cam Jun 12 '18 at 12:56
  • A follow up question. If I want to query a nested filed, how do I do so in this way? for example `filled.Host` I don't manage to take my json defined properties and can't put a dot in the name as well – Green Jun 12 '18 at 16:14
  • Best to ask a separate question for this. Field names with dots can be handled with Dictionarys or JObject. Take a look at nested query docs: https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/nested-query-usage.html – Russ Cam Jun 12 '18 at 22:15
  • I still struggle to get it right. So i did, https://stackoverflow.com/questions/50839110/how-to-build-a-unit-test-for-nest-6-x-with-nested-values – Green Jun 13 '18 at 13:58