测试传递给 NEST (elasticsearch) 的参数
Test for parameter passed to NEST (elasticsearch)
我正在使用 NEST 进行弹性搜索查询。
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
方法中有逻辑。
有什么方法可以检查 boolQuery
对象中传递给 ElasticClient 的内容吗?
我已经使用 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
进行一些检查。但我不知道这是否可能或如何完成。还是有其他方法可以做到这一点?
TL;DR使用派生QueryVisitor
。请参阅下面的 Edit2。
发现问题已经得到解答。它与 NEST 无关,但与测试 lambda 表达式有关。
不可能:C# Moq Unit Testing with Lambda Expression or Func delegate
可以做的是测试将发送到 elasticsearch 的 JSON 请求,但是您需要实际的 ElasticClient
:
可以做的是将逻辑放在自己的 method/class 中。但是你只是为了测试而编写代码,我不喜欢这样。喜欢:
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
的列表,它们是不可测试的,因为它也是用 lambda 表达式生成的。虽然总比没有好,但它仍然不是测试 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,并且是一个查询?我已经知道了。对于第二个,我可以断言一些附加信息,例如字段名称 (blacklistedfor) 和后缀(关键字)。
断言字符串表示并不完美,但聊胜于无。
编辑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
,然后在测试方法中断言。
我正在使用 NEST 进行弹性搜索查询。
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
方法中有逻辑。
有什么方法可以检查 boolQuery
对象中传递给 ElasticClient 的内容吗?
我已经使用 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
进行一些检查。但我不知道这是否可能或如何完成。还是有其他方法可以做到这一点?
TL;DR使用派生QueryVisitor
。请参阅下面的 Edit2。
发现问题已经得到解答。它与 NEST 无关,但与测试 lambda 表达式有关。 不可能:C# Moq Unit Testing with Lambda Expression or Func delegate
可以做的是测试将发送到 elasticsearch 的 JSON 请求,但是您需要实际的 ElasticClient
:
可以做的是将逻辑放在自己的 method/class 中。但是你只是为了测试而编写代码,我不喜欢这样。喜欢:
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
的列表,它们是不可测试的,因为它也是用 lambda 表达式生成的。虽然总比没有好,但它仍然不是测试 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,并且是一个查询?我已经知道了。对于第二个,我可以断言一些附加信息,例如字段名称 (blacklistedfor) 和后缀(关键字)。
断言字符串表示并不完美,但聊胜于无。
编辑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
,然后在测试方法中断言。