我本人和我的大学已经建立了一个数据访问模块,该模块可以对ElasticeSearch(6.2.0)NoSQL数据库进行CRUD和搜索操作。我们使用的是高级客户端NEST(6.2.0)映射到Elasticsearch查询DSL。该模块已在目标框架.NET Standard 2.0中的类库中用C#编码。
在某些方法中,有必要检索存储在ElasticSearch中的索引的索引映射,以便可以使用诸如字段类型和文本属性之类的字段信息来构建对Elasticsearch数据库的搜索查询。我们可以使用Nest的GetMapping方法(返回Nest.IGetMappingResponse)来做到这一点。
我们在执行代码方面没有问题。一切正常。但是,当我们为使用GetMapping方法的方法构建单元测试时,我们无法模拟其返回的响应(IGetMappingResponse)。我最初使用FakeItEasy进行伪造,然后在对象中插入了我需要的一些数据。但是,为了更好地解释我的问题,我创建了一个实现IGetMappingResponse的类来模拟我的响应。当我尝试为IndexMapping的Mapping属性创建 TypeMappings 的实例时出现问题(作为回报,该属性用于模拟的Indices)。我收到一条错误消息,说“ TypMappings”不包含带有0个参数的构造函数。
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,以便测试代码。
答案 0 :(得分:1)
在Nkosi的帮助下,我发现 TypeMappings 具有内部构造函数。知道了这一点,我使用了反射创建了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;
}