2011-09-22 19 views
10

とNHibernateはQueryOverは、次の行が、null参照で失敗してモックここでは暗いです - 私はnHibernateとMoqには比較的新しいので、私は正しい情報を得るために何をgoogleにするのかよくわかりません。は、テストは時に部品番号

答えて

1

私は上記のコードが正しいとは思わない。 AFAIK QueryOverは、ISessionインターフェースの拡張メソッドであり、MoockやRhinoMockのような従来のMockingツールではそうでないような拡張メソッドをMockできません。

+0

「QueryOver」は拡張メソッドではありません。あなたは 'クエリ'を考えている – Vadim

2

QueryOverをモックしようとしないでください。その代わりに、内部的にQueryOverを使用するリポジトリインタフェースを定義し、そのインタフェースをモックします。

4

これはお勧めできません。 mock the types you don't ownしないでください。その代わりにRepositoryを導入し、そのインタフェースをドメイン/ビジネス言語に基づいて実装し、NHibernateを使用して実装する必要があります。実装では、ICriteria、HQL、QueryOver、Linqなどを使用できます。この決定は、リポジトリを消費するコードからカプセル化され、隠されるということです。

インターフェイス+ Real ORM + RealまたはFakeデータベースの組み合わせをテストする統合テストを書くことができます。リポジトリとデータアクセスのテストについては、thisthisの回答をご覧ください。リポジトリインタフェースを模擬することができるので、リポジトリを使用するコードのテストも簡単です。

テスト容易性以外のこのアプローチの利点は何ですか?彼らはお互いにある程度関係しています:

  • Separation of Concerns。データアクセス層で解決されたデータアクセスの問題(リポジトリ実装)。
  • ルーズカップリング。残りのシステムは、今日のデータアクセスツールに結合されていません。リポジトリの実装をHibernateからraw SQL、Azure、Webサービスに切り替える可能性があります。スイッチする必要がない場合でも、レイヤーを切り替える必要があるかのように設計すれば、レイヤリングはより効果的です。
  • 可読性。リポジトリインタフェース定義を含むドメインオブジェクトは、ビジネス/ドメイン言語に基づいています。
+0

downvoterはコメントしますか? – Dmitry

3

私は過去にいくつかのアプローチを使用してきました。 1つの方法は、他の人が示唆しているように、あなたのクエリをカプセル化するモック/スタブであるRepositoryクラスを作成することです。この問題の1つの問題は、非常に柔軟性がなく、ソリューションのようなストアドプロシージャを持つことです。ただし、これはデータベースではなくコードです。

私が試みた最近の解決策は、QueryOverメソッドをスタブするときに提供するQueryOverスタブを作成することです。私は返されるべき項目のリストを提供することができます。このアプローチを使用する場合、単体テストだけでなく、実際にクエリが動作するかどうかをテストする統合テストを行うべきです。

public class QueryOverStub<TRoot, TSub> : IQueryOver<TRoot, TSub> 
{ 
    private readonly TRoot _singleOrDefault; 
    private readonly IList<TRoot> _list; 
    private readonly ICriteria _root = MockRepository.GenerateStub<ICriteria>(); 

    public QueryOverStub(IList<TRoot> list) 
    { 
     _list = list; 
    } 

    public QueryOverStub(TRoot singleOrDefault) 
    { 
     _singleOrDefault = singleOrDefault; 
    } 

    public ICriteria UnderlyingCriteria 
    { 
     get { return _root; } 
    } 

    public ICriteria RootCriteria 
    { 
     get { return _root; } 
    } 

    public IList<TRoot> List() 
    { 
     return _list; 
    } 

    public IList<U> List<U>() 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOver<TRoot, TRoot> ToRowCountQuery() 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOver<TRoot, TRoot> ToRowCountInt64Query() 
    { 
     throw new NotImplementedException(); 
    } 

    public int RowCount() 
    { 
     return _list.Count; 
    } 

    public long RowCountInt64() 
    { 
     throw new NotImplementedException(); 
    } 

    public TRoot SingleOrDefault() 
    { 
     return _singleOrDefault; 
    } 

    public U SingleOrDefault<U>() 
    { 
     throw new NotImplementedException(); 
    } 

    public IEnumerable<TRoot> Future() 
    { 
     return _list; 
    } 

    public IEnumerable<U> Future<U>() 
    { 
     throw new NotImplementedException(); 
    } 

    public IFutureValue<TRoot> FutureValue() 
    { 
     throw new NotImplementedException(); 
    } 

    public IFutureValue<U> FutureValue<U>() 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOver<TRoot, TRoot> Clone() 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOver<TRoot> ClearOrders() 
    { 
     return this; 
    } 

    public IQueryOver<TRoot> Skip(int firstResult) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot> Take(int maxResults) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot> Cacheable() 
    { 
     return this; 
    } 

    public IQueryOver<TRoot> CacheMode(CacheMode cacheMode) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot> CacheRegion(string cacheRegion) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> And(Expression<Func<TSub, bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> And(Expression<Func<bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> And(ICriterion expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> AndNot(Expression<Func<TSub, bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> AndNot(Expression<Func<bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOverRestrictionBuilder<TRoot, TSub> AndRestrictionOn(Expression<Func<TSub, object>> expression) 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOverRestrictionBuilder<TRoot, TSub> AndRestrictionOn(Expression<Func<object>> expression) 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOver<TRoot, TSub> Where(Expression<Func<TSub, bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> Where(Expression<Func<bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> Where(ICriterion expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> WhereNot(Expression<Func<TSub, bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> WhereNot(Expression<Func<bool>> expression) 
    { 
     return this; 
    } 

    public IQueryOverRestrictionBuilder<TRoot, TSub> WhereRestrictionOn(Expression<Func<TSub, object>> expression) 
    { 
     return new IQueryOverRestrictionBuilder<TRoot, TSub>(this, "prop"); 
    } 

    public IQueryOverRestrictionBuilder<TRoot, TSub> WhereRestrictionOn(Expression<Func<object>> expression) 
    { 
     return new IQueryOverRestrictionBuilder<TRoot, TSub>(this, "prop"); 
    } 

    public IQueryOver<TRoot, TSub> Select(params Expression<Func<TRoot, object>>[] projections) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> Select(params IProjection[] projections) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> SelectList(Func<QueryOverProjectionBuilder<TRoot>, QueryOverProjectionBuilder<TRoot>> list) 
    { 
     return this; 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> OrderBy(Expression<Func<TSub, object>> path) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, path); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> OrderBy(Expression<Func<object>> path) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, false); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> OrderBy(IProjection projection) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, projection); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> OrderByAlias(Expression<Func<object>> path) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, true); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> ThenBy(Expression<Func<TSub, object>> path) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, path); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> ThenBy(Expression<Func<object>> path) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, false); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> ThenBy(IProjection projection) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, projection); 
    } 

    public IQueryOverOrderBuilder<TRoot, TSub> ThenByAlias(Expression<Func<object>> path) 
    { 
     return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, true); 
    } 

    public IQueryOver<TRoot, TSub> TransformUsing(IResultTransformer resultTransformer) 
    { 
     return this; 
    } 

    public IQueryOverFetchBuilder<TRoot, TSub> Fetch(Expression<Func<TRoot, object>> path) 
    { 
     return new IQueryOverFetchBuilder<TRoot, TSub>(this, path); 
    } 

    public IQueryOverLockBuilder<TRoot, TSub> Lock() 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOverLockBuilder<TRoot, TSub> Lock(Expression<Func<object>> alias) 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path, Expression<Func<U>> alias) 
    { 
     return new QueryOverStub<TRoot, U>(_list); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path, Expression<Func<U>> alias, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path, Expression<Func<U>> alias) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) 
    { 
     return new QueryOverStub<TRoot, U>(new List<TRoot>()); 
    } 

    public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<TSub, object>> path, Expression<Func<object>> alias) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<TSub, object>> path, Expression<Func<object>> alias, JoinType joinType) 
    { 
     return this; 
    } 

    public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) 
    { 
     return this; 
    } 

    public IQueryOverSubqueryBuilder<TRoot, TSub> WithSubquery 
    { 
     get { return new IQueryOverSubqueryBuilder<TRoot, TSub>(this); } 
    } 

    public IQueryOverJoinBuilder<TRoot, TSub> Inner 
    { 
     get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.InnerJoin); } 
    } 

    public IQueryOverJoinBuilder<TRoot, TSub> Left 
    { 
     get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.LeftOuterJoin); } 
    } 

    public IQueryOverJoinBuilder<TRoot, TSub> Right 
    { 
     get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.RightOuterJoin); } 
    } 

    public IQueryOverJoinBuilder<TRoot, TSub> Full 
    { 
     get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.FullJoin); } 
    } 
} 
+0

データアクセスをカプセル化するモック可能でテスト可能なリポジトリはストアドプロシージャと似ていますか?むしろ、その場所全体にQueryOverを広めることをお勧めしますか?それは「ドメイン層」を破壊し、その責任をUIとデータアクセス層に広げます。それは確かに超柔軟性があります:http://en.wikipedia.org/wiki/Big_ball_of_mud – Dmitry

+2

@ Dimitry、いくつかの点。はい、すべてのクエリを保持するリポジトリは、格納されたprocsのセットとまったく同じです。同じエンティティをクエリする必要があり、2つのパラメータを使用する必要がある場合はどうなりますか?または、彼はちょうど投影を望んでいるかもしれない?必要に応じてクエリを使用すると、「ドメイン層を破壊する」ドメインエンティティには依然としてビジネスロジックが含まれています。 NHibernateのほかに、すでにデータアクセスの抽象化があります。なぜあなたはそれをさらに抽象化する必要があると感じますか?テストを簡単にしますが、リファクタリングが難しくなります。 – Vadim

+0

@DimitryはOrenのこれらの記事もチェックしていますhttp://ayende.com/blog/4784/architecting-in-the-pit-of-doom-the-evils-of-the-repository-abstraction-layer http: /ayende.com/blog/4783/reviewing-oss-project-whiteboard-chatndash-the-select-n-1-issue – Vadim

1

最近、私が代わりに保護された仮想メソッドに.QueryOverを呼び出すコードを()に移動し、XYZから継承し、メソッドをオーバーライドし、空のリストまたは何を返す自分TestableXYZを構築してきました。このようにして、テストのためだけにリポジトリが必要ない。

関連する問題