Sto usando Web Api OData v4 sul server e OData Client code generator sul client. Funziona bene, ma non so come testare il codice sul client.Come testare il client OData?
Sul server espongo un "Levels" dbSet.
Ecco un frammento di codice sul client:
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();
}
}
sto accettando il contenitore odata generato dal modello T4 come parametro per il costruttore, al fine di essere in grado di Mock in qualche modo.
test di unità, qui è dove mi sono perso:
[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());
}
Quindi, in questo test di unità voglio solo per testare la logica all'interno del metodo GetRootLevels, non voglio fare un test di integrazione o di una servizio di self hosting, voglio solo testare il metodo con i dati in memoria.
Come faccio a prendere in giro la classe generata dal client OData che è in realtà una classe DataServiceContext?
sto usando Moq, ma può essere qualsiasi cosa, (libero o almeno inclusi in VS edizione professionale)
Edit: Ecco l'implementazione di ODataContainer (ricordate che questo è generata automaticamente dal cliente OData)
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));
}
}
}
Si potrebbe garantire di non ricevere nulla DefaultContainer testare le classi che usano questo costruttore. Quindi, modificare il parametro per utilizzare un'interfaccia (IDefaultContainer o qualcosa di simile). Quindi puoi testare GetRootLevels confrontando l'oggetto return con quello che hai impostato sulla tua classe mock. – dcidral
Grazie, farò un tentativo. – Tuco
Per farlo funzionare devo prendere in giro la proprietà Levels che è una DataServiceQuery, che ha solo getter. Sto ancora pensando –
Tuco