2009-09-17 3 views
5

単体テストの目的でDataServiceQueryをモックできますか?DataServiceQueryの模擬<TElement>

ロング詳細は以下のとおりです。 は私たちのモデルのストレージをカプセル化するADO.NETのDataServiceにコントローラの会談は、(例えば、酒のために、我々は顧客のリストを読み込むことがあります)ASP.NET MVCアプリケーションを、想像してみてください。サービスを参照すると、我々はたDataServiceContextを継承生成されたクラスを取得します:コントローラは、可能性が

namespace Sample.Services 
{ 
    public partial class MyDataContext : global::System.Data.Services.Client.DataServiceContext 
    { 
    public MyDataContext(global::System.Uri serviceRoot) : base(serviceRoot) { /* ... */ } 

    public global::System.Data.Services.Client.DataServiceQuery<Customer> Customers 
    { 
     get 
     { 
     if((this._Customers==null)) 
     { 
      this._Customers = base.CreateQuery<Customer>("Customers"); 
     } 
     return this._Customers; 
     } 
    } 
    /* and many more members */ 
    } 
} 

namespace Sample.Controllers 
{ 
    public class CustomerController : Controller 
    { 
    private IMyDataContext context; 

    public CustomerController(IMyDataContext context) 
    { 
     this.context=context; 
    } 

    public ActionResult Index() { return View(context.Customers); } 
    } 
} 

あなたが見ることができるように、私はそうIMyDataContextインスタンスを受け取るコンストラクタを使用しました

[TestFixture] 
public class TestCustomerController 
{ 
    [Test] 
    public void Test_Index() 
    { 
    MockContext mockContext = new MockContext(); 
    CustomerController controller = new CustomerController(mockContext); 

    var customersToReturn = new List<Customer> 
    { 
     new Customer{ Id=1, Name="Fred" }, 
     new Customer{ Id=2, Name="Wilma" } 
    }; 
    mockContext.CustomersToReturn = customersToReturn; 

    var result = controller.Index() as ViewResult; 

    var models = result.ViewData.Model; 

    //Now we have to compare the Customers in models with those in customersToReturn, 
    //Maybe by loopping over them? 
    foreach(Customer c in models) //*** LINE A *** 
    { 
     //TODO: compare with the Customer in the same position from customersToreturn 
    } 
    } 
} 

MockContextとMyDataContextが同じインタフェースIMyDataContextを実装する必要があります:私たちは私たちのユニットテストでモックを使用することができる

namespace Sample.Services 
{ 
    public interface IMyDataContext 
    { 
    DataServiceQuery<Customer> Customers { get; } 
    /* and more */ 
    } 
} 

我々がしようとMockContextクラスを実装する場合しかし、我々はそれが我々が見つかったデータ型だというだけの理由IMyDataContextインターフェイスで使用している、明確にしている、(DataServiceQueryの性質に起因する問題に遭遇私たちが始めた自動生成されたMyDataContextクラスにあります)。私たちが書くしようとした場合:お客様に

public class MockContext : IMyDataContext 
{ 
    public IList<Customer> CustomersToReturn { set; private get; } 

    public DataServiceQuery<Customer> Customers { get { /* ??? */ } } 
} 

ゲッター我々は、DataServiceQueryインスタンスをインスタンス化CustomersToReturnのお客様を移入し、それを返すようにしたいと思います。

1〜 DataServiceQueryにはpublicコンストラクタがありません。 DataServiceContextでCreateQueryを呼び出す必要があります。私はMockContextが同様たDataServiceContextを継承し、かつ、使用するDataServiceQueryを取得するからCreateQueryを呼び出して作成した場合、私は反復処理しようとすると、サービスおよびクエリは、有効なURIに関連付けする必要があり、MSDN

2〜を見ますまたはクエリ内のオブジェクトにアクセスすると、そのURIに対して試行して実行します。私のようなMockContext変更言い換えれば、:そして、

namespace Sample.Tests.Controllers.Mocks 
{ 
    public class MockContext : DataServiceContext, IMyDataContext 
    { 
    public MockContext() :base(new Uri("http://www.contoso.com")) { } 

    public IList<Customer> CustomersToReturn { set; private get; } 

    public DataServiceQuery<Customer> Customers 
    { 
     get 
     { 
     var query = CreateQuery<Customer>("Customers"); 
     query.Concat(CustomersToReturn.AsEnumerable<Customer>()); 
     return query; 
     } 
    } 
    } 
} 

http://www.contoso.comは、当社のサービスをホストしていないため、ユニットテストでは、我々は、LINE Aとしてマークされた行にエラーが発生します。 LINE Aがモデル内の要素の数を取得しようとしても、同じエラーが発生します。 ありがとうございます。

答えて

0

[免責事項 - 私はTypemockで働く]

あなたはモックフレームワークを使用して検討していますか?

あなたはDataServiceQueryの偽のインスタンスを作成するために、Typemockアイソレータを使用することができます。

var fake = Isolate.Fake.Instance<DataServiceQuery>(); 

そして、あなたは似た偽たDataServiceContextを作成し、それが代わりにそれを継承しようとしているの振る舞いだ設定することができます。

+0

ドロール、アイデアの感謝が、当分の間、我々は、任意のモックフレームワークを使用していません。私たちは、それに頼らない解決策があるかどうかを知ることに興味があります。それでも、ありがとうございます – FOR

+0

モッキングフレームワークを使用しない特定の理由はありますか? –

+0

一般的に、特別な理由はありません。私たちはそれを紹介するかもしれませんが、この特定の仕事のために夜通しそれをするつもりはありません。ですから、今のところ私たちは嘲笑の枠組みを追加せずに解決策を見出そうとしています。 – FOR

4

Iは、2つの実装とインターフェースIDataServiceQueryを作成することによって、これを解決:私は以前にDataServiceQueryを使用していたであろうどこ私は、IDataServiceQueryを使用

  • DataServiceQueryWrapper
  • MockDataServiceQuery

public interface IDataServiceQuery<TElement> : IQueryable<TElement>, IEnumerable<TElement>, IQueryable, IEnumerable 
{ 
    IDataServiceQuery<TElement> Expand(string path); 

    IDataServiceQuery<TElement> IncludeTotalCount(); 

    IDataServiceQuery<TElement> AddQueryOption(string name, object value); 
} 

DataServiceQueryWrapperはその後、デリゲートに渡されたクエリへのすべての機能をそれのコンストラクタでDataServiceQueryを取り、同様に、MockDataServiceQueryは、クエリにそれができるIQueryable及び代表者のすべてを取ります。

モックIDataServiceQueryの方法については、私は現在、thisを返していますが、あなたが望むならば、あなたは機能を模擬するために何かをすることができます。

たとえば

// (in DataServiceQueryWrapper.cs) 
public IDataServiceQuery<TElement> Expand(string path) 
{ 
    return new DataServiceQueryWrapper<TElement>(_query.Expand(path)); 
} 

 

// (in MockDataServiceQuery.cs) 
public IDataServiceQuery<TElement> Expand(string path) 
{ 
    return this; 
}