2016-04-28 6 views
0

ユニットテストの最初の開発プロセスを練習しているので、私はユニットテスト中にこの質問をしました。ユニットテスト、LINQを使用したデータベースカウント

データベース内の特定のテーブルに含まれるアイテムを確認またはアサートするテストを作成する必要があります。また、それはパラメータを持っています。

[TestMethod] 
    public void verify_items_count() 
    { 
     //Arrange 
     Mock<IRepository> Repo = new Mock<IRepository>(); 
     Repo.Setup(t => t.Query().Count(r => r.Id == "**WHAT SHOULD I PUT HERE IF THIS IS ONLY A MOCK**")).Returns(12); 

     //Act 
     //Assert 
    } 

私はそれが私たちのすべては、それがDBに呼び出していないことを知っているので、また、そのパラメータを有する12を返した場合、それはチェックを主張するならば、それはどれもセンスなりますように思えます。私はそれを12に設定しました。

まず単体テストの書き方を教えてください。 統合テストに参加する予定があると思っていました。 しかし、私はすべてが単体テストで始めるべきであることを読んだ。だから私は道があると信じている。

+1

これで実際にどのクラスをテストしていますか?あなたはモックを試しているように見えます。 –

+0

私は実際にそれを取得しません。私はデータベース内の項目を数えなければならない。しかし、私はDBに接続する必要はないので。私はそれを嘲笑しなければならない。実際のコードでは、おそらく私はそれを設定しているLINQクエリの種類を使用します。 – user1960948

+1

カウントコードは自分で書くものなのですか?あなた自身のコードだけをテストしなければなりません。 –

答えて

0

あなたのリポジトリを偽造しないでください。代わりにIRepositoryを実装するDummyRepositoryを作成します。あなたはこの

public interface IRepository 
{ 
    void Add<T>(T entity) where T : class; 
    T Get<T>(int id, params Expression<Func<T, object>>[] includes) where T : BaseEntity; 
    IQueryable<T> GetAll<T>(params Expression<Func<T, object>>[] includes) where T : class; 
    void Remove<T>(T entity) where T : class; 
    void SaveChanges(); 
} 

ようIRepository strucutureを持っている場合は、あなたのDummyRepositoryは、あなたがこの

public class BaseEntity 
{ 
    public int Id { get; set; } 
} 
のようである動作するように、この例のためBaseEntityを必要とするような方法でこの

public class DummyRepository : IRepository 
{ 
    private readonly Dictionary<Type, Object> _database; 

    public DummyRepository() 
    { 
     _database = new Dictionary<Type, object>(); 
    } 

    public void Add<T>(T entity) where T : class 
    { 
     var table = GetEntityTable<T>(); 

     var entityBase = entity as BaseEntity; 
     if (entityBase == null) 
      throw new NotImplementedException("You must inherit from entity base"); 

     if (entityBase.Id == 0) 
     { 
      var idToUse = table.Any() ? table.Max(x => (x as BaseEntity).Id) + 1 : 1; 
      typeof(BaseEntity).GetProperty("Id").SetValue(entityBase, idToUse); 
      table.Add(entity); 
     } 
     else 
     { 
      var itemInList = table.FirstOrDefault(x => (x as BaseEntity).Id == entityBase.Id); 
      if (itemInList == null) 
       table.Add(entity); 
      else 
      { 
       var itemIndex = table.IndexOf(itemInList); 
       table[ itemIndex ] = entity; 
      } 
     } 
    } 


    private List<T> GetEntityTable<T>() where T : class 
    { 
     List<T> table; 
     if (_database.ContainsKey(typeof(T))) 
      table = (List<T>)_database[ typeof(T) ]; 
     else 
     { 
      table = new List<T>(); 
      _database.Add(typeof(T), table); 
     } 
     return table; 
    } 

    public T Get<T>(int id, params Expression<Func<T, object>>[] includes) where T : BaseEntity 
    { 
     if (!_database.ContainsKey(typeof(T))) 
      return null; 
     return ((List<T>)_database[ typeof(T) ]).FirstOrDefault(x => x.Id == id); 
    } 

    public IQueryable<T> GetAll<T>(params Expression<Func<T, object>>[] includes) where T : class 
    { 
     if (_database.ContainsKey(typeof(T))) 
      return ((List<T>)_database[ typeof(T) ]).AsQueryable(); 
     return new List<T>().AsQueryable(); 
    } 

    public void Remove<T>(T entity) where T : class 
    { 
     if (_database.ContainsKey(entity.GetType())) 
      ((IList)_database[ entity.GetType() ]).Remove(entity); 
    } 

    public void SaveChanges() { } 
} 

を行う必要があります

テスト開始時にはAddのデータが必要です。クエリを確認できるテストを書くことができれば幸いです。

あなたがサービスクラスを持っていないので、以下のコードは歓迎されませんが、私はここであなたの使い方の例を挙げてjusyです。

IRepository repository = new DummyRepository(); 
repository.Add(new BaseEntity { Id = 1 }); 
var service = new Service(repository); 
0

ナイーブ最初のテストは、おそらくカバーの下

[TestMethod] 
    public void verify_items_count() 
    { 
     //Arrange 
     var expectedCount = 3; 
     var repository = MakeRepositoryWithElements(expectedCount); 

     //Act 
     var actualCount = repository.Count(); 

     //Assert 
     Assert.AreEqual(expectedCount, actualCount); 
    } 

だろう、MakeRepositoryWithElements(n)本当リポジトリをインスタンス化

  • に管理する必要があります。あなたはCount()の実際の実装をテストしたいので、モックやスタブではありません。それがテストのすべてです。

  • n個の要素をリポジトリに配置します。

教科書、これを行うの長ったらしい方法は、おそらく次のようになります。

  1. が本当のデータベースに対してSQLクエリとして直接MakeRepositoryWithElements()Count()を実装します。あなたがしたい場合は、実際のDBに対する

    • テストが遅く、データのクリーンアップの多くを必要とします

    • テストは、あなたのTDDサイクルのリファクタリングの段階では

    • を渡し、その実現連続したテストのデータソースと同じデータベースを再利用します。

    • お使いのプラットフォームでは、クエリが重労働を起こし、データベーステーブルではなくオブジェクトのコレクションを公開するSQLの上に抽象概念が提供されています。私。ある種のDatabaseContextです。便利なことに、データベースコンテキストには、自分の高速のメモリ内バージョンを作成するためのインプリメンテーションが可能なインターフェースがあります。テストでは、フルバージョンのDatabaseContextではなく、そのバージョンにリポジトリを接続します。

それぞれが厳密にシングルReponsibility原則に準拠してオブジェクトまでだから、リファクタリングう - DatabaseContextは、基礎となる永続化技術についてである一方で、オブジェクトのコレクションに関するリポジトリが唯一の理由 - とテストを迅速かつで実行メモリ。あなたが経験豊富な開発者の方、または既にお使いのシステムでは、このようなリポジトリを実装している場合は、これらの線に沿って何かを

public class WhateverRepository 
{ 
    private IDatabaseContext _dbContext; 

    public WhateverRepository(IDatabaseContext databaseContext) 
    { 
    _dbContext = databaseContext; 
    } 

    public int Count() 
    { 
    // This is possible because the context exposes collections of objects to us 
    return _dbContext.Whatevers.Count(); 
    } 
} 

public WhateverRepository MakeRepositoryWithElements(int elementCount) 
{ 
    var context = new InMemoryDatabaseContext(); 
    for (int i = 0; i < elementCount; i++) 
    { 
    context.Whatevers.Add(new Whatever()); 
    } 
    return new WhateverRepository(context); 
} 

、あなたはおそらく、直接洗練されたソリューションにジャンプします。最後に

Count()プラットフォームは、あなたが(カウント与えるので、既にデータが、オブジェクトのコレクションの形であなたにさらされている場合は任意のロジックを必要としない些細なワンライナーであることに注意してください)について無料です。したがって、でも、このテストをスキップしたい場合は、を試してみてください。まだTDDの練習をしたい場合や、テストを最初のデカップリング実装にする「スターター」として使いたい場合は除きます。リポジトリといくつかのテストヘルパメソッドがあります。

関連する問題