# Mocking the .NET Client for ExistsResponse in unit tests

**URL:** <https://discuss.elastic.co/t/mocking-the-net-client-for-existsresponse-in-unit-tests/371915>\
**Category:** Elasticsearch\
**Tags:** language-clients, runtime-fields\
**Created:** [December 12, 2024, 12:35pm UTC](https://discuss.elastic.co/t/mocking-the-net-client-for-existsresponse-in-unit-tests/371915 "2024-12-12T12:35:31Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Moni\_Hazarika](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/moni_hazarika/32/124158_2.png) [@Moni\_Hazarika](https://discuss.elastic.co/u/Moni_Hazarika)\
**Post date:** [December 12, 2024, 12:35pm UTC](https://discuss.elastic.co/t/mocking-the-net-client-for-existsresponse-in-unit-tests/371915/1 "2024-12-12T12:35:31Z")

</div>

Hello Everyone,

I am using .NET 8 and "Elastic.Clients.Elasticsearch" Version="8.15.6" (not NEST)  
For mocking we are using NSubstitute(not Moq)

I tried to go through multiple blogs and even the github repo for .NET client tests but could not find anything concrete around how to mock the sealed class for exists response i.e. public sealed partial class ExistsResponse : ElasticsearchResponse

We could successfully use it for SearchResponse and MappingResponse but could not make it work for ExistsResponse

```auto
var searchResponse = new SearchResponse<Dictionary<string, object>>();
var response = TestableResponseFactory.CreateSuccessfulResponse(searchResponse, 200);
or
var mockIndexMappingRecord = new IndexMappingRecord
{
    Mappings = mockTypeMapping // The mappings we just defined
 };
var mockDictionary = new Dictionary<IndexName, IndexMappingRecord>
{
  { "indexName", mockIndexMappingRecord }
 };
var getMappingResponse = TestableResponseFactory.CreateResponse(
        new GetMappingResponse(mockDictionary),
        200, // HTTP 200 OK from Elasticsearch
        true // Valid response flag
      );

```

Below are the options we tried and failed

1. TestableResponseFactory - This gives the compile error for Exists = true

```auto
var responsee = TestableResponseFactory.CreateResponse(
  new ExistsResponse
  {
    Exists = true
  },
  200, // HTTP 200 OK
  true // Valid response flag
);
_elasticClient
            .ExistsAsync(
              Arg.Any<Elastic.Clients.Elasticsearch.Indices>(), // Match any Indices argument
              Arg.Any<System.Threading.CancellationToken>() // Match any CancellationToken argument
            )
            .Returns(Task.FromResult(responsee));

```

1. Having a ReflectionWrapper. For reflection its complicated the things.

```auto
var apiCallDetails = ReflectionWrapper.CreateInstanceWithPrivateConstructor<ApiCallDetails>();
ReflectionWrapper.SetPrivateFieldOrProperty(apiCallDetails, "HttpStatusCode", 200);
var response = new ExistsResponse();
ReflectionWrapper.SetPrivateFieldOrProperty(response, "ApiCallDetails", apiCallDetails);
_elasticClient
            .ExistsAsync(
              Arg.Any<Elastic.Clients.Elasticsearch.Indices>(),
              Arg.Any<System.Threading.CancellationToken>()
            )
            .Returns(Task.FromResult(response)); // Return the Task-wrapped ExistsResponse
var result = await _elasticClient.ExistsAsync(
            Arg.Any<Elastic.Clients.Elasticsearch.Indices>(),
            Arg.Any<System.Threading.CancellationToken>()
          );
bool exists = result.Exists;

```

We get runtime errors:

```auto
System.InvalidOperationException: Field or property 'HttpStatusCode' not found on type 'Elastic.Transport.ApiCallDetails'.
System.InvalidOperationException
Field or property 'HttpStatusCode' not found on type 'Elastic.Transport.ApiCallDetails'.

```

Had also tried the in-memory connection though not recommended.  
In-memory git link :

> <https://github.com/elastic/elasticsearch-net/issues/5714#issuecomment-855940949>
>
> Hi,
> 
> I need to mock some methods and properties in \`Nest.IElasticClient\` inter…face that is used in my repo. As example I need to stub the \`Indices.Exists()\` method to return an \`ExistsResponse \`having an \`Exists \`property returning \`true\`.
> 
> The problem is that the concrete class has no interface implementation, nor setter on the Exists property, and is not declared virtual neither in Nest lib:
> \`\`\`C#
> public class ExistsResponse : ResponseBase
> {
> public ExistsResponse();
> public bool Exists { get; }
> }
> 
> public ExistsResponse Exists(Indices index, Func\<IndexExistsDescriptor, IIndexExistsRequest\> selector = null);
> \`\`\`
> 
> So for the mocking I tried to set the property anyway on the concrete class, but it failed with all the following methods, I have no idea on how to do ...
> \`\`\`C#
> /\* Fail with exception :
> System.NotSupportedException : Unsupported expression: x =\> x.Exists
> Non-overridable members (here: ExistsResponse.get\_Exists) may not be used in setup / verification expressions.
> \*/
> var mock1 = new Mock\<ExistsResponse\>();
> obj.SetupGet(f =\> f.Exists).Returns(true);
> 
> /\* Fail with exception :
> System.NotSupportedException : Unsupported expression: f =\> f.Exists
> Non-overridable members (here: ExistsResponse.get\_Exists) may not be used in setup / verification expressions.
> \*/
> var mock2 = Mock.Of\<ExistsResponse\>(x =\> x.Exists == true);
> 
> /\* Fail with exception :
> System.ArgumentException : Property set method not found.
> \*/
> var mock3 = new ExistsResponse();
> var property = typeof(ExistsResponse).GetProperty("Exists", BindingFlags.Public | BindingFlags.Instance);
> property.SetValue(mock3, true);
> 
> /\* Fail with exception :
> System.NullReferenceException (setter is null)
> \*/
> var mock4 = new ExistsResponse();
> var setter = property.GetSetMethod(true);
> setter.Invoke(mock4, new object\[\] { true });
> 
> 
> // My Mock on the Indices.Exists method
> var elasticMock = new Mock\<IElasticClient\>();
> elasticMock
> .Setup(x =\> x.Indices.Exists(It.IsAny\<string\>(), null))
> .Returns(/\*\*\* my stubbed object here \*\*\*/); // \<== how to stub the concrete class to return a ExistsResponse.Exists = true ?
> 
> var repositoryMock = new Mock\<GeocodedCityElkRepository\>(elasticMock.Object, new NullLogger\<GeocodedCityElkRepository\>());
> repositoryMock
> .Setup(x =\> x.Get(It.IsAny\<int\>(), It.IsAny\<Func\<QueryContainerDescriptor\<GeocodedCity\>, QueryContainer\>\>()))
> .Returns(Task.FromResult(new List\<GeocodedCity\>().AsReadOnly() as IReadOnlyCollection\<GeocodedCity\>));
>      
> // Act
> var exception = await Assert.ThrowsAsync\<GeocodingException\>(() =\>
> repositoryMock.Object.GetDensity("11111", "city", "FR"));
> 
> \`\`\`
> 
> Well unless I missed something, I'm stuck ...
> 
> \*\*Describe the solution you'd like\*\*
> Allow to mock concrete class (making property virtual) or at least provide interface for returned objects like ExistsResponse.
> 
> \`\`\`C#
> public interface IExistsResponse
> {
> bool Exists { get; }
> }
> 
> \[DataContract\]
> public class ExistsResponse : ResponseBase, IExistsResponse
> {
> public ExistsResponse();
> public bool Exists { get; }
> }
> \`\`\`
> 
> \*\*Describe alternatives you've considered\*\*
> Do not test my repository ...
> 
> \*\*Additional context\*\*
> 
> My libs :
> \`\`\`
> Nest 7.12.1
> Moq 4.15.2
> XUnit 2.4.1
> .Net 5
> \`\`\`
> Here is a \[subset of my repo\](https://github.com/elastic/elasticsearch-net/issues/5442#issuecomment-809622652)

Can some one guide how to proceed?

Regards,  
Moni

---

<div class="post-metadata">

**Author:** ![flobernd](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/flobernd/32/124877_2.png) [@flobernd](https://discuss.elastic.co/u/flobernd)\
**Post date:** [December 12, 2024, 1:13pm UTC](https://discuss.elastic.co/t/mocking-the-net-client-for-existsresponse-in-unit-tests/371915/2 "2024-12-12T13:13:52Z")

</div>

Hi @Moni_Hazarika ,

Just a few words related to this style of testing in general:

IMO you are mocking on the wrong abtraction level. Currently, you are trying to mimic the Elasticsearch client/server behavior - which in the end does not really verify anything meaningful.

Do you have some kind of repository pattern in your application? If yes, then this would be the place where I could imagine using mocks.

As for your concrete problem:

Reflection will be the only way to mock this response and they way you are trying it looks good to me. I'm not sure why your reflection helpers can't find the `HttpStatusCode` property as I don't know your implementation.

All the code related to `Elastic.Transport` is available here:

> **[GitHub - elastic/elastic-transport-net: Transport classes and utilities shared among .NET...](https://github.com/elastic/elastic-transport-net)**
>
> Transport classes and utilities shared among .NET Elastic client libraries

`ApiCallDetails.HttpStatusCode` is a `public` property with an `internal` setter. Maybe your reflection setter does the wrong thing here?

---

<div class="post-metadata">

**Author:** ![Moni\_Hazarika](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/moni_hazarika/32/124158_2.png) [@Moni\_Hazarika](https://discuss.elastic.co/u/Moni_Hazarika)\
**Post date:** [December 13, 2024, 9:50am UTC](https://discuss.elastic.co/t/mocking-the-net-client-for-existsresponse-in-unit-tests/371915/3 "2024-12-13T09:50:43Z")

</div>

Thanks @flobernd for your response.

Yes we have the repository pattern and need to mock the Elasticsearch client and response to that level.  
We made some changes to the way we called reflection helpers and now we have passed through the invalid operation exception. Below is the latest code where we have combined Reflection with ResponseFactory.

```auto
// Step 1: Create an instance of ApiCallDetails using private/internal constructor
          var apiCallDetails = ReflectionWrapper.CreateInstanceWithPrivateConstructor<ApiCallDetails>();

          // Step 2: Set 'HttpStatusCode' to 200 (which will cause 'HasSuccessfulStatusCode' to return true)
          ReflectionWrapper.SetPrivateFieldOrProperty(apiCallDetails, "HttpStatusCode", 200);

          // Step 3: Set 'HasSuccessfulStatusCode' to true
          ReflectionWrapper.SetPrivateFieldOrProperty(apiCallDetails, "HasSuccessfulStatusCode", true);

          // Step 4: Create an instance of ExistsResponse
          var response = new ExistsResponse();

          // Step 5: Inject ApiCallDetails into ExistsResponse using reflection
          ReflectionWrapper.SetPrivateFieldOrProperty(response, "ApiCallDetails", apiCallDetails);

          //ReflectionWrapper.SetPrivateFieldOrProperty(response, "IsValidResponse", true);

          var existresponse = TestableResponseFactory.CreateResponse(
            response,
            200, // HTTP 200 OK from Elasticsearch
            true // Valid response flag
          );

          // Step 6: Mock ExistsAsync for the indices and cancellation token
          _elasticClient
            .ExistsAsync(Arg.Any<Elastic.Clients.Elasticsearch.Indices>(), Arg.Any<System.Threading.CancellationToken>())
            .Returns(Task.FromResult(existresponse));

```

Currently when the test class hits the actual call here  
`await _elasticClient.Indices.ExistsAsync(IndexName)`  
We are now getting null response. If you have mocked the client and response correctly then it should be using our instance and SHOULD NOT give me null.  
Due to which test case fails with NPE as further down the line we have references using **response.Exists**.

Our sample reflection wrapper class below:

```auto
public static class ReflectionWrapper
    {
      /// <summary>
      /// Creates an instance of an object using its non-public constructor.
      /// </summary>
      /// <typeparam name="T">The type of object to create.</typeparam>
      /// <returns>The created object instance.</returns>
      public static T CreateInstanceWithPrivateConstructor<T>() where T : class
      {
        var type = typeof(T);
        var constructorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

        if (constructorInfo == null)
        {
          throw new InvalidOperationException($"No private or internal constructor found for type '{type}'.");
        }

        // Create an instance using the constructor
        return (T)constructorInfo.Invoke(null); // No parameters needed for the constructor
      }

      /// <summary>
      /// Sets a private or internal field or property on an object using reflection.
      /// </summary>
      /// <param name="obj">The object instance.</param>
      /// <param name="propertyName">The name of the private/internal property or field to set.</param>
      /// <param name="value">The value to set.</param>
      public static void SetPrivateFieldOrProperty<T>(T obj, string propertyName, object value)
      {
        var type = obj?.GetType();

        // Try to find a Property first
        var propertyInfo = type?.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        if (propertyInfo != null && propertyInfo.CanWrite)
        {
          propertyInfo.SetValue(obj, value);
          return;
        }

        // If property was not found, try to find a field
        var fieldInfo = type?.GetField(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        if (fieldInfo != null)
        {
          fieldInfo.SetValue(obj, value);
          return;
        }

        throw new InvalidOperationException($"Field or property '{propertyName}' not found on type '{type}'.");
      }
    }

```
