微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 Moq 进行 Elasticsearch Nest 单元测试:无法模拟具体类

如何解决使用 Moq 进行 Elasticsearch Nest 单元测试:无法模拟具体类

我需要在我的存储库中使用的 nest.IElasticclient 接口中模拟一些方法属性。 例如,我需要存根 Indices.Exists() 方法以返回一个 ExistsResponse,其 Exists 属性返回 true。

问题在于具体类没有接口实现,也没有 Exists 属性上的 setter,并且在 nest lib 中也没有声明为 virtual:

public class ExistsResponse : ResponseBase
{
    public ExistsResponse();
    public bool Exists { get; }
}

public ExistsResponse Exists(Indices index,Func<IndexExistsDescriptor,IIndexExistsRequest> selector = null);

因此,对于模拟,我无论如何都尝试在具体类上设置属性,但是以下所有方法都失败了,我不知道该怎么做...

/* 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 ?

我的库:

nest 7.12.1
Moq 4.15.2
XUnit 2.4.1
.Net 5

感谢您的帮助

解决方法

模拟你不拥有的东西通常不好,但如果你想模拟弹性客户端响应,最好的方法是使用 InMemryConnection,你可以像这样用 InMemryConnection 实例化一个新的 elasticClient:

InMemory 弹性客户端:

var connection = new InMemoryConnection();
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool,connection);
var client = new ElasticClient(settings);

然后你需要伪造响应并要求客户端返回它,如下所示:

var response = new
{
    took = 1,timed_out = false,_shards = new
    {
        total = 2,successful = 2,failed = 0
    },hits = new
    {
        total = new { value = 25 },max_score = 1.0,hits = Enumerable.Range(1,25).Select(i => (object)new
        {
            _index = "project",_type = "project",_id = $"Project {i}",_score = 1.0,_source = new { name = $"Project {i}" }
        }).ToArray()
    }
};

var responseBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response));
var connection = new InMemoryConnection(responseBytes,200); 
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool,connection).DefaultIndex("project");
var client = new ElasticClient(settings);

var searchResponse = client.Search<Project>(s => s.MatchAll());

您可以找到有关 InMemoryConnection here 的更多信息。

如果您想正确地遵循不要嘲笑您不拥有的东西,您需要执行以下步骤:

  1. ElasticClient 和 ElasticClient 的所有 RequestResponses 包裹在这个库中,然后您可以轻松模拟您需要的内容。
  2. 您应该使用集成测试来测试您的包装类,以确保您的包装类按预期工作。

更新:

对于模拟 Indices.Exists,您只需发送 200 OK,因此您只需执行以下操作:

var connection = new InMemoryConnection(responseBytes,200); 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?