2012-03-30 9 views
1

私はWebフォームとMVPパターンを使用してショッピングウェブサイトを3層アーキテクチャで作成しています。私はまた、プレゼンターclass.forテストフレームワークの私はNUnitを使用して私のモック私はNSubstitudeを使用して検証と型鋳造を行うことにしました。ここに私のカテゴリのモデルクラスは次のとおりです。こここれはプレゼンターをテストするための正しい方法です

//we're doing Dependency injection here. 
    public abstract class BaseRepository 
    { 
     EntityContext context; 
     public BaseRepository() 
     { 
      context = new EntityContext(); 
     } 
     public EntityContext Context 
     { 
      get { return context; } 
     } 
    } 
    public class CategoryRepository : BaseRepository 
    { 
     public int Add(long id, string name) 
     { 
      Category cat = new Category(); 
      cat.Id = id; 
      cat.Name = name; 
      Context.Category.Add(cat); 
      Context.SaveChanges(); 
     } 
    } 

がカテゴリプレゼンターである:

public class CategoryPresenter : BasePresenter //has nothing but a dependency property to Logger 
    { 
     BaseRepository _model; 
     IView _view; 
     public CategoryPresenter(IView view) 
     { 
      _model = new CategoryRepository(); 
      _view = view; 
     } 
     public void Add() 
     { 
      //havn't passed the tests yet since i'm not sure if i'm on the correct path. 
      //whatever validation, loggin and type casting will go here. 
      _model.Add(_view.CategoryId, _view.CategoryName); 
     } 
    } 

、ここでは、プレゼンターのためのテストクラスです:

[Test] 
    public void Add_NullId_ThrowException() 
    { 
     _view.CategoryId.Returns(p => null); 
     _view.CategoryName.Returns(p => "test"); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_EmptyId_ThrowException() 
    { 
     _view.CategoryId.Returns(p => ""); 
     _view.CategoryName.Returns(p => "test"); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_SpaceOnlyId_ThrowException() 
    { 
     _view.CategoryId.Returns(p => " "); 
     _view.CategoryName.Returns(p => "test"); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_InvalidLowBoundId_ThrowException() 
    { 
     _view.CategoryId.Returns(p => "-1"); 
     _view.CategoryName.Returns(p => "test"); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_InvalidHighBoundId_ThrowException() 
    { 
     _view.CategoryId.Returns(p => long.MaxValue.ToString() + "1"); 
     _view.CategoryName.Returns(p => "test"); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 

    [Test] 
    public void Add_EmptyName_ThrowException() 
    { 
     _view.CategoryId.Returns(p => "1"); 
     _view.CategoryName.Returns(p => ""); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_NullName_ThrowException() 
    { 
     _view.CategoryId.Returns(p => "1"); 
     _view.CategoryName.Returns(p => null); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_SpaceOnlyName_ThrowException() 
    { 
     _view.CategoryId.Returns(p => "1"); 
     _view.CategoryName.Returns(p => " "); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 
    [Test] 
    public void Add_NumberOnlyName_ThrowException() 
    { 
     _view.CategoryId.Returns(p => "1"); 
     _view.CategoryName.Returns(p => "123"); 
     Assert.Throws(typeof(InvalidOperationException), _presenter.Add()); 
    } 

私は正確にテストしてい?私は、テストクラスはどのように見えるのでしょうか?私は何かが欠けている?これはあまりにも大きいですか? 「空をテストする必要はありません」、またはテストやコードに関連するその他の問題のようなものですか?私のコード全体やアーキテクチャーの中で何か間違っていることがわかったら、あなたが私を正しければそれを感謝します。ありがとう!

更新: IViewは.aspxページに継承されます。コード上では、ボタンを押すことによってユーザーがトリガーされるクリックイベントの内部からプレゼンターメソッドを呼び出すだけです。私はまだそれを行っていないメモリについては。単にTDDに固執しています。

+0

誰がIViewを継承していますか?誰がIViewにメモリを送信していますか? – Pankaj

+0

更新を参照してください。 "メモリ"とは、取得したデータを意味します。 – jim

答えて

1

私はアプリケーション層(プレゼンターが住んでいる)から検証ロジックを削除し、それをリポジトリが存在するドメイン層に抽出します。

プレゼンターの中で検証を行うのではなく、プレゼンターが必要なバリデーターを呼び出させるようにしてください。

プレゼンターの単体テストについては、プレゼンターにバリデーターモックオブジェクトを提供し、データに対して正しい検証方法が呼び出されていることを確認します。

だから、あなたは二つのことをテストする必要があります。 1)試験プレゼンターがビュー 2からのデータでバリデータを呼び出す場合)

テストは次のようになります。自分でバリデータをテストします。

プレゼンター(クラスCategoryPresenterTests)の場合

:私たちはバリデータがビューからこの正確なデータと呼ばれているだけで、表示さからコンクリートの入力を気にしないでください

[Test] 
public void Add_CallsTheValidatorWithDataFromTheView() 
{ 
    _viewMock.CategoryId.Returns(p => "id"); 
    _viewMock.CategoryName.Returns(p => "name"); 

    _presenter.Add(); 

    _categoryValidatorMock.Verify(x=>x.Validate("id", "name"), Times.Once); 
} 

[Test] 
public void Add_ForwardsValidationExceptions() 
{ 
    _viewMock.CategoryId.Returns(p => "id"); 
    _viewMock.CategoryName.Returns(p => "name"); 

    _categoryValidatorMock.Setup(x=>x.Validate(...)).Throws<ValidationException>(); 

    Assert.Throws<ValidationException>(() => _presenter.Add()); 
} 

注意と結果(この場合は例外または例外なし)が返されます。バリデータについては

(クラスCategoryValidatorTestsは基本的にすべてのあなたの現在のテストはここに行く):上記の擬似コードであるので、私はNSubstitutes構文を知らない

[Test] 
public void NullId_ThrowsException() { 
    string id = null; 
    string name = "test"; 
    Assert.Throws<ValidationException>(() => _validator.Validate(id, name)); 
} 

注..あなたがそれを解読することができます願っています: )

私はプレゼンターの中にリポジトリを作成するのではなく、(IViewのように)コンストラクターを通してインターフェイスを注入します。その後、モックオブジェクトを提供し、バリデータと同様に、それらが発表者によって正しく呼び出されていることを確認します。

上記のすべては、プレゼンターの外で検証ロジックを再利用できるようにする必要があります。プレゼンターからはいくらか複雑になり、モデルとビューの仲介とワークフローの処理という実際の目的にもっと集中できます。 。

+0

first>リポジトリインタフェースを挿入すると、私のビューはコンクリートリポジトリを提供しなければなりません。これは、私のビューがもうダミーオブジェクトではないことを意味します。私は正しい? 2番目> validate()メソッドを持つIValidatorという名前のインターフェイスを追加し、私のドメインオブジェクトにプレゼンターの_model.validate()を実装させることができますか? – jim

+1

1)ビューは、プレゼンターよりも少ないレポジトリの具体的な実装について知っておく必要があります。誰が何を作成するかを知るにはASP.NET WebFormsについて十分に知りません。しかし、NInjectのようなIoCコンテナを調べたいときは、独自のプレゼンターを作成する必要があります(つまり、ビューとプレゼンターの両方を作成できるユーザーは誰もいません)。そうすれば、ビューはIoCコンテナにプレゼンタを作成するよう依頼することができ、コンテナは依存関係の解決に気を配ります(これは起動時に一度設定するだけです)。 – stmax

+1

2)いくつかの賛否両論で可能です。コンテキストによっては異なるバリデーションが必要な場合もありますので、それらを分離しておきたいと思います。また、この実装では、無効なオブジェクトを作成してそれらを検証できるようにする必要があります。ビジネスルールで名前が空でないことが必要な場合は、空の名前を持つエンティティは存在しません。しかし、この実装では、それを検証するために、この実装を作成する必要があります。 :) – stmax

関連する問題