C# 如何对OData客户端进行单元测试?
我在服务器和客户端上使用Web Api OData v4。它工作正常,但我不知道如何在客户端上测试代码 在服务器上,我公开了一个“Levels”数据库集 以下是客户端上的代码片段:C# 如何对OData客户端进行单元测试?,c#,unit-testing,odata,moq,odata-v4,C#,Unit Testing,Odata,Moq,Odata V4,我在服务器和客户端上使用Web Api OData v4。它工作正常,但我不知道如何在客户端上测试代码 在服务器上,我公开了一个“Levels”数据库集 以下是客户端上的代码片段: public class LevelViewer { public virtual ODataContainer Container{get;set;} //t4 template generated public LevelViewer(ODataContainer container=null)
public class LevelViewer
{
public virtual ODataContainer Container{get;set;} //t4 template generated
public LevelViewer(ODataContainer container=null)
{
if(container==null)
{
Container=new ODataContainer(new Uri("http://blabla"));
}
}
//I want to test this (actually there are more things, this is an example)
public List<Level> GetRootLevels()
{
return ODataContainer.Levels.Where(l=>l.IsRoot).ToList();
}
}
公共类LevelViewer
{
公共虚拟ODataContainer容器{get;set;}//t4模板已生成
公共级别查看器(ODataContainer容器=null)
{
if(容器==null)
{
容器=新ODataContainer(新Uri(“http://blabla"));
}
}
//我想测试一下(实际上还有更多的东西,这是一个例子)
公共列表GetRootLevels()
{
返回ODataContainer.Levels.Where(l=>l.IsRoot.ToList();
}
}
我接受T4模板生成的odata容器作为构造函数的参数,以便能够以某种方式模拟它
单元测试,这里是我迷路的地方:
[TestMethod]
public void LevelsVMConstructorTest()
{
List<Level>levels=new List<Level>();
levels.Add(new Level(){Id=1,LevelId=1,Name="abc",IsRoot=True});
IQueryable<Level>levelsIQ=levels.AsQueryable<Level>();
//?
var odataContainerMock=new Mock<ODataContainer>();
odataContainerMock.Setup(m=>m.Levels).Returns( I DON'T KNOW );
//I want to get here
LevelViewer lv = new LevelViewer(odataContainerMock.Object);
Assert.IsTrue(lv.GetRootLevels().Any());
}
[TestMethod]
public void LevelsVMConstructorTest()
{
Listlevels=新列表();
添加(新级别(){Id=1,LevelId=1,Name=“abc”,IsRoot=True});
IQueryablelevelsIQ=levels.AsQueryable();
//?
var odataContainerMock=new Mock();
设置(m=>m.Levels).返回(我不知道);
//我想到这里
LevelViewer lv=新的LevelViewer(odataContainerMock.Object);
Assert.IsTrue(lv.GetRootLevels().Any());
}
所以在这个单元测试中,我只想测试GetRootLevels方法内部的逻辑,我不想做集成测试或自托管服务,我只想用内存中的数据测试这个方法
如何模拟OData客户机生成的类(实际上是DataServiceContext类)
我正在使用Moq,但它可以是任何东西(免费或至少包含在VS专业版中)
编辑:下面是ODataContainer的实现(记住这是由Odata客户端自动生成的)
公共部分类ODataContainer:global::Microsoft.OData.Client.DataServiceContext
{
///
///初始化新的ODataContainer对象。
///
[全局::System.CodeDom.Compiler.GeneratedCodeAttribute(“Microsoft.OData.Client.Design.T4”、“2.4.0”)]
公共ODataContainer(全局::System.Uri serviceRoot):
基本(serviceRoot,全局::Microsoft.OData.Client.ODataProtocolVersion.V4)
{
this.ResolveName=new global::System.Func(this.ResolveNameFromType);
this.ResolveType=new global::System.Func(this.ResolveTypeFromName);
this.OnContextCreated();
this.Format.LoadServiceModel=generateddmModel.GetInstance;
this.Format.UseJson();
}
部分无效OnContextCreated();
///
///因为为此服务引用配置了命名空间
///在Visual Studio中,与中所示的不同
///服务器架构,使用类型映射器在两者之间进行映射。
///
[全局::System.CodeDom.Compiler.GeneratedCodeAttribute(“Microsoft.OData.Client.Design.T4”、“2.4.0”)]
受保护的全局::System.Type ResolveTypeFromName(字符串类型名称)
{
global::System.Type resolvedType=this.DefaultResolveType(typeName,“WebServiceOData”,“Constraint\u Data\u Feed.WebServiceOData”);
如果((resolvedType!=null))
{
返回解析类型;
}
resolvedType=this.DefaultResolveType(typeName,“DAL.Models”,“Constraint\u Data\u Feed.DAL.Models”);
如果((resolvedType!=null))
{
返回解析类型;
}
返回null;
}
///
///因为为此服务引用配置了命名空间
///在Visual Studio中,与中所示的不同
///服务器架构,使用类型映射器在两者之间进行映射。
///
[全局::System.CodeDom.Compiler.GeneratedCodeAttribute(“Microsoft.OData.Client.Design.T4”、“2.4.0”)]
受保护的字符串ResolveNameFromType(全局::System.Type clientType)
{
全局::Microsoft.OData.Client.OriginalNameAttribute OriginalNameAttribute=(全局::Microsoft.OData.Client.OriginalNameAttribute)全局::System.Linq.Enumerable.SingleOrDefault(全局::Microsoft.OData.Client.Utility.GetCustomAttribute(clientType,typeof(全局::Microsoft.OData.Client.OriginalNameAttribute),true);
if(clientType.Namespace.Equals(“Constraint_Data_Feed.webservicecodata”,global::System.StringComparison.Ordinal))
{
if(originalNameAttribute!=null)
{
返回string.Concat(“WebServiceOData.”,originalNameAttribute.OriginalName);
}
返回string.Concat(“webservicedata.”,clientType.Name);
}
if(clientType.Namespace.Equals(“Constraint_Data_Feed.DAL.Models”,global::System.StringComparison.Ordinal))
{
if(originalNameAttribute!=null)
{
返回string.Concat(“DAL.Models.”,originalNameAttribute.OriginalName);
}
返回string.Concat(“DAL.Models.”,clientType.Name);
}
返回null;
}
///
///架构中没有级别的注释。
///
[全局::System.CodeDom.Compiler.GeneratedCodeAttribute(“Microsoft.OData.Client.Design.T4”、“2.4.0”)]
[全局::Microsoft.OData.Client.OriginalNameAttribute(“级别”)]
公共全局::Microsoft.OData.Client.DataServiceQuery级别
{
得到
{
如果((此._Levels==null))
{
这个._Levels=base.CreateQuery(“Levels”);
}
返回此。_级别;
}
}
[全局::System.CodeDom.Compiler.GeneratedCodeAttribute(“Microsoft.OData.Client.Design.T4”、“2.4.0”)]
私有全局::Microsoft.OData.Client.DataServiceQuery\u级别;
///
///架构中没有级别的注释。
///
[全局::System.CodeDom.Compiler.GeneratedCodeAttribute(“Microsoft.OData.Client.Design.T4”、“2.4.0”)]
public void AddToLevels(全局::Constraint\u Data\u Feed.DAL.Models)。
public partial class ODataContainer : global::Microsoft.OData.Client.DataServiceContext
{
/// <summary>
/// Initialize a new ODataContainer object.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
public ODataContainer(global::System.Uri serviceRoot) :
base(serviceRoot, global::Microsoft.OData.Client.ODataProtocolVersion.V4)
{
this.ResolveName = new global::System.Func<global::System.Type, string>(this.ResolveNameFromType);
this.ResolveType = new global::System.Func<string, global::System.Type>(this.ResolveTypeFromName);
this.OnContextCreated();
this.Format.LoadServiceModel = GeneratedEdmModel.GetInstance;
this.Format.UseJson();
}
partial void OnContextCreated();
/// <summary>
/// Since the namespace configured for this service reference
/// in Visual Studio is different from the one indicated in the
/// server schema, use type-mappers to map between the two.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
protected global::System.Type ResolveTypeFromName(string typeName)
{
global::System.Type resolvedType = this.DefaultResolveType(typeName, "WebServiceOData", "Constraint_Data_Feed.WebServiceOData");
if ((resolvedType != null))
{
return resolvedType;
}
resolvedType = this.DefaultResolveType(typeName, "DAL.Models", "Constraint_Data_Feed.DAL.Models");
if ((resolvedType != null))
{
return resolvedType;
}
return null;
}
/// <summary>
/// Since the namespace configured for this service reference
/// in Visual Studio is different from the one indicated in the
/// server schema, use type-mappers to map between the two.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
protected string ResolveNameFromType(global::System.Type clientType)
{
global::Microsoft.OData.Client.OriginalNameAttribute originalNameAttribute = (global::Microsoft.OData.Client.OriginalNameAttribute)global::System.Linq.Enumerable.SingleOrDefault(global::Microsoft.OData.Client.Utility.GetCustomAttributes(clientType, typeof(global::Microsoft.OData.Client.OriginalNameAttribute), true));
if (clientType.Namespace.Equals("Constraint_Data_Feed.WebServiceOData", global::System.StringComparison.Ordinal))
{
if (originalNameAttribute != null)
{
return string.Concat("WebServiceOData.", originalNameAttribute.OriginalName);
}
return string.Concat("WebServiceOData.", clientType.Name);
}
if (clientType.Namespace.Equals("Constraint_Data_Feed.DAL.Models", global::System.StringComparison.Ordinal))
{
if (originalNameAttribute != null)
{
return string.Concat("DAL.Models.", originalNameAttribute.OriginalName);
}
return string.Concat("DAL.Models.", clientType.Name);
}
return null;
}
/// <summary>
/// There are no comments for Levels in the schema.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
[global::Microsoft.OData.Client.OriginalNameAttribute("Levels")]
public global::Microsoft.OData.Client.DataServiceQuery<global::Constraint_Data_Feed.DAL.Models.Level> Levels
{
get
{
if ((this._Levels == null))
{
this._Levels = base.CreateQuery<global::Constraint_Data_Feed.DAL.Models.Level>("Levels");
}
return this._Levels;
}
}
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
private global::Microsoft.OData.Client.DataServiceQuery<global::Constraint_Data_Feed.DAL.Models.Level> _Levels;
/// <summary>
/// There are no comments for Levels in the schema.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
public void AddToLevels(global::Constraint_Data_Feed.DAL.Models.Level level)
{
base.AddObject("Levels", level);
}
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
private abstract class GeneratedEdmModel
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
private static global::Microsoft.OData.Edm.IEdmModel ParsedModel = LoadModelFromString();
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
private const string Edmx = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""DAL.Models"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Level"">
<Key>
<PropertyRef Name=""Id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" />
<Property Name=""LevelId"" Type=""Edm.Int32"" />
<NavigationProperty Name=""Sublevels"" Type=""Collection(DAL.Models.Level)"" />
<NavigationProperty Name=""Machines"" Type=""Collection(DAL.Models.Machine)"" />
</EntityType>
<EntityType Name=""Machine"">
<Key>
<PropertyRef Name=""Id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" />
<Property Name=""LevelId"" Type=""Edm.Int32"" />
<NavigationProperty Name=""Level"" Type=""DAL.Models.Level"">
<ReferentialConstraint Property=""LevelId"" ReferencedProperty=""Id"" />
</NavigationProperty>
<NavigationProperty Name=""Parts"" Type=""Collection(DAL.Models.Part)"" />
</EntityType>
<EntityType Name=""Part"">
<Key>
<PropertyRef Name=""Id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" />
<NavigationProperty Name=""Machines"" Type=""Collection(DAL.Models.Machine)"" />
</EntityType>
</Schema>
<Schema Namespace=""WebServiceOData"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""ODataContainer"">
<EntitySet Name=""Levels"" EntityType=""DAL.Models.Level"">
<NavigationPropertyBinding Path=""Sublevels"" Target=""Levels"" />
</EntitySet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
public static global::Microsoft.OData.Edm.IEdmModel GetInstance()
{
return ParsedModel;
}
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
private static global::Microsoft.OData.Edm.IEdmModel LoadModelFromString()
{
global::System.Xml.XmlReader reader = CreateXmlReader(Edmx);
try
{
return global::Microsoft.OData.Edm.Csdl.EdmxReader.Parse(reader);
}
finally
{
((global::System.IDisposable)(reader)).Dispose();
}
}
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.4.0")]
private static global::System.Xml.XmlReader CreateXmlReader(string edmxToParse)
{
return global::System.Xml.XmlReader.Create(new global::System.IO.StringReader(edmxToParse));
}
}
}
[TestMethod]
public void LevelsVMConstructorTest()
{
using (ShimsContext.Create())
{
List<Level> levels = new List<Level>();
levels.Add(new Level() { Id = 1, LevelId = 1, Name = "abc", IsRoot = true });
var levelsIQ = levels.AsQueryable();
var fakeDataServiceQuery = new System.Data.Services.Client.Fakes.ShimDataServiceQuery<Level>();
fakeDataServiceQuery.ProviderGet = () => levelsIQ.Provider;
fakeDataServiceQuery.ExpressionGet = () => levelsIQ.Expression;
fakeDataServiceQuery.ElementTypeGet = () => levelsIQ.ElementType;
fakeDataServiceQuery.GetEnumerator = levelsIQ.GetEnumerator;
var defaultContainerMock = new Mock<DefaultContainer>();
defaultContainerMock.Setup(m => m.Levels).Returns(fakeDataServiceQuery);
LevelViewer lv = new LevelViewer(odataContainerMock.Object);
Assert.IsTrue(lv.GetRootLevels().Any());
}
}