2015-12-04 28 views
8

Tôi đang sử dụng Web Api OData v4 trên máy chủ và OData Client code generator trên máy khách. Nó hoạt động tốt, nhưng tôi không biết làm thế nào để kiểm tra mã trên máy khách.Làm thế nào để kiểm tra đơn vị OData Client?

Trên máy chủ, tôi hiển thị dbSet "Cấp độ".

Dưới đây là một đoạn mã trên máy khách:

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(); 
    } 
} 

Tôi chấp nhận container OData tạo ra bởi các mẫu T4 như một tham số cho các nhà xây dựng để có thể Mock nó bằng cách nào đó.

Đơn vị kiểm tra, đây là nơi tôi đang mất:

[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()); 
    } 

Vì vậy, trong bài kiểm tra đơn vị này, tôi chỉ muốn kiểm tra logic bên trong phương pháp GetRootLevels, tôi không muốn thực hiện một thử nghiệm tích hợp hoặc một dịch vụ tự lưu trữ, tôi chỉ muốn thử nghiệm phương thức với dữ liệu trong bộ nhớ.

Làm cách nào để giả tạo lớp khách được tạo OData mà thực sự là lớp DataServiceContext?

Tôi đang sử dụng Moq, nhưng nó có thể được bất cứ điều gì, (miễn phí hoặc ít nhất có trong phiên bản chuyên nghiệp VS)

Edit: Đây là việc thực hiện các ODataContainer (nhớ này là autogenerated bởi OData client)

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)); 
     } 
    } 
}  
+2

Bạn có thể đảm bảo để không bao giờ nhận được một DefaultContainer rỗng kiểm tra các lớp học sử dụng constructor này. Và sau đó, thay đổi tham số để sử dụng một giao diện (IDefaultContainer hoặc một cái gì đó tương tự). Sau đó, bạn có thể kiểm tra GetRootLevels bằng cách so sánh đối tượng trả về là bất cứ điều gì bạn thiết lập trên lớp giả của bạn. – dcidral

+0

Cảm ơn, tôi sẽ thử. – Tuco

+0

Để làm việc đó, tôi phải giả lập thuộc tính Levels là một DataServiceQuery , chỉ có getter. Tôi vẫn đang suy nghĩ – Tuco

Trả lời

7

C'tor của DataServiceQuery là riêng tư, do đó tôi không thể giả mạo nó bằng cách sử dụng Moq.

tôi đã sử dụng MsFakes như một công cụ mã dệt miễn phí để giải quyết vấn đề này:

[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()); 

    } 
} 
+0

Cảm ơn, tôi sẽ cho nó một thử, tôi sẽ cho bạn biết kết quả. – Tuco

+0

Đây phải là câu trả lời nhưng có vẻ như [Tôi cần VS phiên bản cao cấp để bật MSFakes] (http: //visualstudio.uservoice.com/forums/121579-visual-studio/đề xuất/2919309-cung cấp-microsoft-fakes-with-all-visual-studio-edi) và tôi có ấn bản Chuyên nghiệp, tôi sẽ cố gắng để có được một bản sao của phiên bản cao cấp và tôi ' Tôi sẽ trả lời câu trả lời này – Tuco

+0

@ATM ah Tôi không biết vấn đề đặc biệt này ... Bạn có thể thêm một thuộc tính ảo sẽ hiển thị 'IEnumerable 'rồi sử dụng nó trong mã của bạn:' public virtual IEnumerable GetLevels {get {return Levels;}} '. Với cách tiếp cận này, bạn không cần bất kỳ công cụ dệt mã nào. BTW Tôi đã đánh dấu 'Levels' là phương pháp ảo trong thử nghiệm của mình ... –

Các vấn đề liên quan