2010-11-10 3 views
2

J'ai un service de données WCF qui expose des interfaces:membres IQueryable du client Mocking WCF

public interface IAccountService 
{ 
    IQueryable<Account> Accounts { get; } 
    IQueryable<Contract> Contracts { get; } 
} 

[DataServiceKey("ID")] 
public class Account 
{ 
    public virtual Guid ID { get; set; } 
    public virtual string AccountName { get; set; } 
    public virtual string Address1 { get; set; } 
    public virtual string Address2 { get; set; } 
    public virtual string City { get; set; } 
    public virtual string State { get; set; } 
    public virtual string Zip { get; set; } 
    public virtual string Phone { get; set; } 
    public virtual string Fax { get; set; } 
    public virtual string Status { get; set; } 
    public virtual DateTime StartDate { get; set; } 
    public virtual IEnumerable<Contract> Contracts { get; set; } 
} 

[DataServiceKey("ID")] 
public class Contract 
{ 
    public virtual Guid ID { get; set; } 
    public virtual string ContractCode { get; set; } 
    public virtual string ContractName { get; set; } 
    public virtual DateTime StartDate { get; set; } 
    public virtual int UnitQty { get; set; } 
    public virtual double UnitPrice { get; set; } 
} 

Je veux se moquer du client de service pour les tests unitaires. Je voudrais écrire un test comme:

[Test] 
public void MockContractsFromAccount() 
{ 
    var acctSvc = new Mock<IAccountService>(); 
    var blah = new Contract[] { new Contract { ContractCode = "BLAH001", ContractName = "blah 1" }, 
     new Contract { ContractCode = "BLAH002", ContractName = "blah 2" } }; 
    var blee = new Contract[] { new Contract { ContractCode = "BLEE001", ContractName = "blee 1" } }; 
    var accts = new Account[] { new Account { AccountName = "blah", State = "WY", Contracts = new DataServiceCollection<Contract>(blah) }, 
     new Account { AccountName = "blee", State = "CO", Contracts = new DataServiceCollection<Contract>(blee) } }; 
    acctSvc.SetupGet(x => x.Accounts).Returns(accts.AsQueryable()); 

    var result = from x in acctSvc.Object.Accounts 
       where x.State == "CO" 
       select x; 
    Assert.That(result, Has.Count.EqualTo(1)); 
    Assert.That(result.First().Contracts, Has.Count.EqualTo(2)); 
    Assert.That(result, Is.All.EquivalentTo(blah)); 
} 

Mais le code échoue à new DataServiceCollection<Contract>(blah) avec le message d'erreur

SomeTests.MockContractsFromAccount: System.ArgumentException: DataServiceContext auquel l'instance DataServiceCollection appartient pourrait pas être déterminé. DataServiceContext doit être soit fourni dans le constructeur DataServiceCollection ou être utilisé pour créer l'objet DataServiceQuery ou QueryOperationResponse qui est la source des éléments dans le DataServiceCollection

Cela semble qu'il devient très compliqué. Existe-t-il un moyen d'avoir Visual Studio générer des interfaces pour le compte & contrat ou pour avoir accts.Contracts retourner un IQueryable<Contract> au lieu de DataServiceCollection<Contract>? Peut-être une autre solution simple pour se moquer de ce service?


Par souci de clarté, Svcutil.exe génère une classe de compte qui ressemble à ceci:

public class Account 
{ 
    public Guid ID { get; set; } 
    public string AccountName { get; set; } 
    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public string State { get; set; } 
    public string Zip { get; set; } 
    public string Phone { get; set; } 
    public string Fax { get; set; } 
    public string Status { get; set; } 
    public DateTime StartDate { get; set; } 
    // It descends from IEnumerable<Contract> 
    public DataServiceCollection<Contract> Contracts { get; set; } 
} 

Répondre

-1

Comme la Contracts propriété est de type IEnumerable, vous pouvez créer une collection dénombrable.

Ainsi, au lieu de

Contracts = new DataServiceCollection<Contract>(blah) 

il suffit d'utiliser

Contracts = new [] { blah } 

Cela vous permettra serez déconnecté dans vos objets truqués.

+0

Cela semble être une bonne idée, sauf que dans le code généré la propriété des contrats est de type DataServicesCollection . Si je peux avoir VS générer une interface IAccount, DataServicesCollection étend IEnumerable . Je n'ai toujours pas vu un moyen d'avoir le code généré implémenter une interface – kelloti

+0

@kelloti: non ce n'est pas le cas. Dmytrii n'a pas aimé ma réponse, même si la sienne et la mienne sont fondamentalement les mêmes: elles sont basées sur le fait que la propriété Contrats est un «IEnumerable », au moins par le code que vous nous avez montré. – rsenna

5

Pour ceux qui ont trouvé cette question par un moteur de recherche.

Pour éliminer l'exception "DataServiceContext ... n'a pas pu être déterminée" lors de la création manuelle d'un DataServiceCollection, utilisez le overloaded constructor avec le paramètre TrackingMode défini sur None.

à savoir,

new DataServiceCollection<Contract>(blah, TrackingMode.None)