Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking an ElasticSearch client using C# Moq

I'm testing my class ElasticUtility which requires an instance of the ElasticClient in order to work properly so I mocked such class and injected it into the ElasticUtility instance (utility)

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

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

This is the actual test code:

[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());
}

I get a Null reference exception when the Moq library calls the .Search() method inside the mocked ElastiClient.

EDIT:

the constructor of ElasticUtility:

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

EDIT: GetPvData() method:

    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();
    }
like image 453
Gianluca Ghettini Avatar asked Aug 18 '15 14:08

Gianluca Ghettini


2 Answers

The NullReferenceException occured because you didn't specify a behavior on search method. Your search method returns null and then you calls .Document on the null.

The way to specify a behavior is as the following:

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

you have to replace my comments with the correct types.

like image 159
Old Fox Avatar answered Oct 18 '22 20:10

Old Fox


Code is from .git here: 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);
like image 38
Jack Avatar answered Oct 18 '22 19:10

Jack