首页 文章

如何模拟Elasticsearch NEST的IGetMappingResponse进行单元测试

提问于
浏览
3

我和我的大学已经 Build 了一个数据访问模块,它可以对ElasticeSearch(6.2.0)NoSQL数据库进行CRUD和搜索操作 . 我们正在使用NEST(6.2.0),一个高级客户端来映射到Elasticsearch查询DSL . 该模块已在C#中编码,在目标框架.NET Standard 2.0中的类库中 .

在某些方法中,有必要检索存储在ElasticSearch中的索引的索引映射,以便可以使用字段类型和文本属性等字段信息来构建对Elasticsearch数据库的搜索查询 . 我们可以通过使用Nest的GetMapping方法(返回Nest.IGetMappingResponse)来完成此操作 .

我们没有执行代码的问题 . 一切正常 . 但是,当我们为使用GetMapping方法的方法构建单元测试时,我们无法模拟它返回的响应(IGetMappingResponse) . 我最初使用FakeItEasy伪造它,然后在对象中插入了我需要的一些数据 . 但是,为了更好地解释我的问题,我创建了一个实现IGetMappingResponse的类来模拟我的响应 . 当我尝试为IndexMapping的Mapping属性创建 TypeMappings 的实例时,问题出现了(返回的是针对模拟的属性指数) . 我收到一条错误说 “’TypMappings’ does not contain a constructor that takes 0 arguments.

public class MockedGetMappingResponse : IGetMappingResponse
    {
        public IReadOnlyDictionary<IndexName, IndexMappings> Indices
        {
            get
            {
                return new ReadOnlyDictionary<Nest.IndexName, Nest.IndexMappings>(new Dictionary<Nest.IndexName, Nest.IndexMappings>
                {
                    ["statuses"] = new IndexMappings
                    {
                        Mappings = new TypeMappings() //Error happens here!!
                    }                      

                });
            }
            set { }
        }

        public IReadOnlyDictionary<IndexName, IndexMappings> Mappings
        {
            get
            {
                return null;
            }
            set { }
        }

        public void Accept(IMappingVisitor visitor)
        {
            // Just a test
        }

        public bool IsValid
        {
            get
            {
                return true;
            }
        }

        public ServerError ServerError
        {
            get
            {
                return null;
            }
        }

        public Exception OriginalException
        {
            get
            {
                return null;
            }
        }

        public string DebugInformation
        {
            get
            {
                return "";
            }
        }

        public IApiCallDetails ApiCall
        {
            get
            {
                return null;
            }
            set
            {
                //do nothing
            }
        }

        public bool TryGetServerErrorReason(out string reason)
        {
            reason = "";
            return false;
        }
    }      

}

当我查找Nest类型 TypeMappings 的定义时,我没有看到构建器构建 . 因此,我假设它应该使用默认值,一个没有参数的构造函数 . 但显然它没有 . 我需要知道如何在IGetMappingResponse中模拟TypeMappings . 如果没有办法创建TypeMappings的实例,我需要知道如何创建一个模拟的IGetMappingResponse到我预期的响应,以便我可以测试我的代码 .

1 回答

  • 1

    在Nkosi的帮助下,我发现 TypeMappings 有一个内部构造函数 . 知道了,我使用Reflection创建了一个TypeMappings实例 . 这是我用来创建对象的代码 .

    IReadOnlyDictionary<TypeName, TypeMapping> backingDictionary = new ReadOnlyDictionary<TypeName, TypeMapping>(new Dictionary<TypeName, TypeMapping>
            {
                [typeName.Name] = typeMapping
    
            });           
    
            Type[] typeMappingsArgs = new Type[] { typeof(IConnectionConfigurationValues), typeof(IReadOnlyDictionary<TypeName, TypeMapping>) };
            object[] typeMappingsInputParams = new object[] { elasticClient.ConnectionSettings, backingDictionary };
            TypeMappings typeMappings = (TypeMappings)typeof(TypeMappings).GetConstructor(
                  BindingFlags.NonPublic | BindingFlags.Instance,
                  null, typeMappingsArgs, null).Invoke(typeMappingsInputParams);
    

    这是创建我的模拟IGetMappingResponse的代码 . 我使用FakeItEasy插入一些信息 .

    private Nest.IGetMappingResponse GetFakeMappingResponse(Nest.IElasticClient elasticClient)
        {
            var fieldName = "fieldName";
            var indexName = "indexName";
            var documentTypeName = "documentTypeName";
    
            var typeMapping = new TypeMapping();
            var properties = new Properties();
            typeMapping.Properties = properties;
    
            var property = new TextProperty();
            property.Name = fieldName;            
    
            PropertyName propertyName = new PropertyName(fieldName);
    
            typeMapping.Properties.Add(propertyName, property);
    
            Type[] typeNameArgs = new Type[] { typeof(string) };
            object[] typeNameInputParams = new object[] { documentTypeName };
            TypeName typeName = (TypeName)typeof(TypeName).GetConstructor(
                  BindingFlags.NonPublic | BindingFlags.Instance,
                  null, typeNameArgs, null).Invoke(typeNameInputParams);
    
    
            IReadOnlyDictionary<TypeName, TypeMapping> backingDictionary = new ReadOnlyDictionary<TypeName, TypeMapping>(new Dictionary<TypeName, TypeMapping>
            {
                [typeName.Name] = typeMapping
    
            });           
    
            Type[] typeMappingsArgs = new Type[] { typeof(IConnectionConfigurationValues), typeof(IReadOnlyDictionary<TypeName, TypeMapping>) };
            object[] typeMappingsInputParams = new object[] { elasticClient.ConnectionSettings, backingDictionary };
            TypeMappings typeMappings = (TypeMappings)typeof(TypeMappings).GetConstructor(
                  BindingFlags.NonPublic | BindingFlags.Instance,
                  null, typeMappingsArgs, null).Invoke(typeMappingsInputParams);
    
            IndexMappings indexMappings = new IndexMappings();
            typeof(IndexMappings).GetProperty("Mappings", BindingFlags.Public | BindingFlags.Instance).SetValue(indexMappings, typeMappings);
    
            ReadOnlyDictionary<Nest.IndexName, Nest.IndexMappings> indices = new ReadOnlyDictionary<Nest.IndexName, Nest.IndexMappings>(new Dictionary<Nest.IndexName, Nest.IndexMappings>
            {
                [indexName] = indexMappings
    
            });
    
            var fakeMappingResponse = A.Fake<IGetMappingResponse>();
            A.CallTo(() => fakeMappingResponse.ServerError).Returns(null);
            A.CallTo(() => fakeMappingResponse.IsValid).Returns(true);
            A.CallTo(() => fakeMappingResponse.Indices).Returns(indices);
    
            return fakeMappingResponse;
        }
    

相关问题