使用C# Moq模拟ElasticSearch客户端

8

我正在测试我的类ElasticUtility,它需要ElasticClient的实例才能正常工作,因此我模拟了这样的类并将其注入到ElasticUtility实例(utility)中。

    private ElasticUtility utility;
    private Mock<IElasticClient> elasticClientMock;
    private string elasticSearchIndexName;

    elasticClientMock = new Mock<IElasticClient>();
    utility = new UhhElasticUtility(elasticClientMock.Object);

这是实际的测试代码:

[Test]
public void GetGetPvDataClientReturnNull()
{
    // arrange
    var groupId = "groupid";
    var startTime = new DateTime(2015, 08, 17, 13, 30, 00);
    var endTime = new DateTime(2015, 08, 17, 13, 40, 00);
    
    // act
    utility.GetPvData(groupId, startTime, endTime);

    // assert
    elasticClientMock.Verify(ec => ec.Search<SegmentRecord>(It.IsAny<Nest.ISearchRequest>()), Times.Once());
}

当Moq库调用模拟的内部的.Search()方法时,我遇到了Null引用异常。

编辑:

ElasticUtility的构造函数:

    protected ElasticUtility(IElasticClient elasticClient, string elasticIndexName)
    {
        this.ElasticClient = elasticClient;
        this.ElasticIndexName = elasticIndexName;
    }

编辑:GetPvData()方法:

    public IEnumerable<dynamic> GetPvData(string groupId, DateTime startTime, DateTime endTime)
    {
        var res = ElasticClient.Search<SegmentRecord>(s => s
            .Index(ElasticIndexName)
            .Filter(f =>
                f.Term(t => t.HistoryId, groupId) &&
                f.Range(i =>
                    i.OnField(a => a.DateTime).LowerOrEquals(startTime))).SortAscending(p => p.DateTime).Size(1)).Documents.ToList();

        return res.ToArray();
    }

可能是因为它被保护了吗? - Gianluca Ghettini
没有受保护的构造函数并不是问题...但我问的是UhhElasticUtility构造函数和GetPvData... - Old Fox
这是GetPvData()的实现。 - Gianluca Ghettini
问题出在.Documents,你没有设置期望值,所以搜索返回了null... - Old Fox
我该如何在这个.Document上添加一个期望? - Gianluca Ghettini
显示剩余3条评论
2个回答

6

NullReferenceException的发生是因为您没有在search方法上指定行为。您的search方法返回null,然后您在null上调用了.Document

指定行为的方式如下:

elasticClientMock.Setup(x => x.Search<SegmentRecord>(
                             It.IsAny</* put here the right Func */>))
        .Returns( /* put here the instance you want to return */);

您需要使用正确的类型替换我的注释。


我无法创建一个Nest.ISearchResponse<SegmentRecord>的实例并将其传递给.Returns()方法。 - Gianluca Ghettini
如果我写:var test = Nest.ISearchResponse<SegmentRecord>();,它会显示“接口名称在此处无效”。哦,原来它是一个接口! - Gianluca Ghettini
即使使用 Nest.SearchResponse<SegmentRecord> 也无法工作。 - Gianluca Ghettini
使用 Moq 创建 Nest.ISearchResponse<SegmentRecord> 实例,或者创建一个自定义类型,如果你使用了 Moq,请确保您没有忘记初始化虚拟对象属性。 - Old Fox
是的,但它没有起作用。我模拟了响应如下: var response = new Mock<Nest.ISearchResponse<SegmentRecord>>(); elasticClientMock.Setup(ec => ec.Search<SegmentRecord>(It.IsAny<Nest.ISearchRequest>())).Returns(response.Object); 但是 .Search() 函数仍然返回 null。 - Gianluca Ghettini

2
代码来自.git在这里:https://gist.github.com/netoisc/5d456850d79f246685fee23be2469155
var people = new List<Person>
{
    new Person { Id = 1 },
    new Person { Id = 2 },
};

var hits = new List<IHit<Person>>
{
    new Mock<IHit<Person>>().Object
};

var mockSearchResponse = new Mock<ISearchResponse<Person>>();
mockSearchResponse.Setup(x => x.Documents).Returns(people);
mockSearchResponse.Setup(x => x.Hits).Returns(hits);

var mockElasticClient = new Mock<IElasticClient>();

mockElasticClient.Setup(x => x
    .Search(It.IsAny<Func<SearchDescriptor<Person>, ISearchRequest>>()))
.Returns(mockSearchResponse.Object);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接