2012-05-01 8 views
3

実際にコードを書いた後にテストを書くのはあまり良くありません。私はユニットテストの初心者であり、単体テストは多くの利点をもたらすかもしれないと感じるので、可能な限りカバーする考えに執着しました。例えば単体テストでカバーしなければならないコード内の場所を見つける方法

、我々はこのコードを持ってみましょう:

public class ProjectsPresenter : IProjectsViewObserver 
{ 
    private readonly IProjectsView _view; 
    private readonly IProjectsRepository _repository; 

    public ProjectsPresenter(IProjectsRepository repository, IProjectsView view) 
    { 
     _view = view; 
     _repository = repository; 
     Start(); 
    } 

    public void Start() 
    { 
     _view.projects = _repository.FetchAll(); 
     _view.AttachPresenter(this); 
    } 

} 

だから、あなたが一般的にテストし、私は上記のコードのその部分に書く必要があります私に答えることができる上記のコードでお探しですか?

コンストラクタの書き込みテストをロールオーバーして、リポジトリのFetchAllが呼び出され、ビューサイトのAttachPresenterが呼び出されていることを確認しています。


POSTのEDITここ

私の見解・インターフェースである:ここで

public interface IProjectsView 
{ 
    List<Project> projects { set; } 
    Project project { set; } 

    void AttachPresenter(IProjectsViewObserver projectsPresenter); 
} 

が表示されます。

public partial class ProjectsForm : DockContent, IProjectsView 
{ 
    private IProjectsViewObserver _presenter; 
    public ProjectsForm() 
    { 
     InitializeComponent(); 
    } 

    public Project project 
    { 
     set 
     { 
      listBoxProjects.SelectedItem = value; 
     } 
    } 

    public List<Project> projects 
    { 
     set 
     { 
      listBoxProjects.Items.Clear(); 
      if ((value != null) && (value.Count() > 0)) 
       listBoxProjects.Items.AddRange(value.ToArray()); 
     } 
    } 

    public void AttachPresenter(IProjectsViewObserver projectsPresenter) 
    { 
     if (projectsPresenter == null) 
      throw new ArgumentNullException("projectsPresenter"); 

     _presenter = projectsPresenter; 
    } 

    private void listBoxProjects_SelectedValueChanged(object sender, EventArgs e) 
    { 
     if (_presenter != null) 
      _presenter.SelectedProjectChanged((Project)listBoxProjects.SelectedItem); 
    } 
} 

POST EDIT#2

これはリポジトリとの対話をテストする方法です。すべてが大丈夫ですか?

[Test] 
    public void ProjectsPresenter_RegularProjectsProcessing_ViewProjectsAreSetCorrectly() 
    { 
     // Arrange 
     MockRepository mocks = new MockRepository(); 
     var view = mocks.StrictMock<IProjectsView>(); 
     var repository = mocks.StrictMock<IProjectsRepository>(); 
     List<Project> projList = new List<Project> { 
      new Project { ID = 1, Name = "test1", CreateTimestamp = DateTime.Now }, 
      new Project { ID = 2, Name = "test2", CreateTimestamp = DateTime.Now } 
     }; 
     Expect.Call(repository.FetchAll()).Return(projList); 
     Expect.Call(view.projects = projList); 
     Expect.Call(delegate { view.AttachPresenter(null); }).IgnoreArguments(); 
     mocks.ReplayAll(); 
     // Act 
     ProjectsPresenter presenter = new ProjectsPresenter(repository, view); 
     // Assert 
     mocks.VerifyAll();    
    } 
+0

鼻緒模型の例は無関係なようです...別の質問に値するかもしれません。とにかく、あなたはおそらくrhino mocksのAAA構文を見たいでしょう。 http://stackoverflow.com/questions/2124175/rhino-mocks-aaa-quick-start –

答えて

2

私はあなたが実際にそれがすべてでテストを書いていないよりはましだコード

を書いた後にテストを書くためにあまりよくないことを知っています。

このメソッドは2つの外部コンポーネントで動作し、その相互作用は(引数の検証に加えて)検証する必要があります。 FetchAllと呼ばれていたかどうかをチェックする(それは何かを返すチェックや - これはProjectsRepositoryテスト自体に属している) - あなたに何の価値を与えないあなたは(間接的に呼び出されたFetchAllかどうかをチェックします)、そのビューのプロジェクトが設定されてチェックしたいです。あなたが必要とするテストは、以下のとおりです。あなたがテストする方法の例:

  • は、プレゼンターが
  • 検証の入力引数

編集添付されていることを確認し、そのビューのプロジェクトは期待値

  • に設定されていることを確認します最初のケース(プロジェクトが設定されている)

    // "RegularProcessing" in test name feels a bit forced; 
    // in such cases, you can simply skip 'conditions' part of test name 
    public void ProjectsPresenter_SetsViewProjectsCorrectly() 
    { 
        var view = MockRepository.GenerateMock<IProjectView>(); 
        var repository = MockRepository.GenerateMock<IProjectsRepository>(); 
        // Don't even need content; 
        // reference comparison will be enough 
        List<Project> projects = new List<Project>(); 
        // We use repository in stub mode; 
        // it will simply provide data and that's all 
        repository.Stub(r => r.FetchAll()).Return(projects); 
        view.Expect(v => v.projects = projects); 
    
        ProjectsPresenter presenter = new ProjectsPresenter(repository, view); 
    
        view.VerifyAllExpecations(); 
    } 
    

    秒の場合、あなたはそのAttachPresenterが有効なオブジェクトと呼ばれているという見解に期待を設定します:

    public void ProjectsPresenter_AttachesPresenterToView() 
    { 
        // Arrange 
        var view = MockRepository.GenerateMock<IProjectView>(); 
        view.Expect(v => v.AttachPresenter(Arg<IProjectsViewObserver>.Is.Anything)); 
        var repository = MockRepository.GenerateMock<IProjectsRepository>(); 
    
        // Act 
        var presenter = new ProjectsPresenter(repository, view); 
    
        // Assert 
        view.VerifyAllExpectations(); 
    } 
    
  • +0

    最初のアイテムと2番目のアイテムを2つの異なるテストに実装するか、1つのテストで実装する必要がありますか? – kseen

    +0

    @kseen:これらは、同じコンポーネントとの対話を除いて**関連していない** 2つのテストである必要があります。 –

    +0

    私の質問の更新を見てください。ビューの詳細を添付しました。発表者が正しく添付されたかどうかテストするにはどうすればいいですか? – kseen

    0

    私はのように、開始時に簡単なテストを追加します。

  • FetchAll()戻って任意の値

  • は、テストの多くを追加しないでください

    • null参照チェック最初にコードを作成しますが、デベロッパーコードとして修正してください突然変異。

    +0

    ヌルリファレンスチェックは良いアイデアのようです!ありがとう!私は 'FetchAll()が任意の値を返す'というあなたの点についてはあまり明確ではない。もっと広く説明していただけますか? – kseen

    +0

    @kseen: 'FetchAll()'が '_view.projects = _repository.FetchAll();'の値を返すかどうかをチェックします。言い換えれば、プログラムが利用可能な*プロジェクトを見つけることができる場合(これはあなたのアプリの重要なポイントであるかどうかわからないが、単に*インテント*である場合) – Tigran

    0

    例外のテストを追加します。 ArgumentException、コーナーケース、およびFetchAll()の通常のケース。

    PS。スタートは公開する必要がありますか?

    +0

    より良い質問は、コンストラクタで。 –

    +0

    あなたのポイントにいくつかのサンプルコードを提供していただけますか? – kseen

    0

    Pexがチェックアウトする価値が興味深いツールです。高いコードカバレッジを持つユニットテストのスイートを生成することができます:http://research.microsoft.com/en-us/projects/pex/。それはあなたのコードに関するあなた自身の知識を置き換えるものではなく、他のものよりもあなたにとって重要なテストシナリオはありませんが、それは素晴らしいことです。

    0

    プロダクションコードを書く前にテストを書くことが、まず、あなたの(開発者)を「自分のコードがいつどのように動作するのか知っていますか?あなたの開発は、作業コードがどのように見えるのか、コード自体ではなく、コードによって得られた実際のビジネス価値に焦点を当てています(何百万人もの人が機能ユーザーの作成と管理に費やされています決して求められなかった、欲しい、または必要とされなかった)。これを行うと、「テスト駆動開発」が行われます。

    純粋なTDDを実行している場合、答えは100%のコードカバレッジです。つまり、単一行の単体テストコードではカバーされていない単一行の実動コードを書くことはありません。

    Visual Studioでは、[テスト] - > [コードカバレッジの分析]を選択すると、カバーしていないすべてのコード行が表示されます。

    実質的に言えば、100%のコードカバレッジを強制するのは必ずしも実現可能ではありません。また、他のコードよりもはるかに重要なコード行があります。各ラインによって提供されるビジネス価値とそのラインの失敗の結果に依存する決定。いくつかの行(ロギングのような)は、他の行より小さな結果を持つかもしれません。

    関連する問題