2010-12-12 13 views
4

私は単体テストの周りに頭を下げるのに苦労しています。私はNerdの夕食とプロasp.netのMVCフレームワークの両方の例を続けてきましたが、すぐに私は自分自身をしようとするとすぐに立ち往生になる。テストとして、単にログイン情報(usenameとpasswordを使用してリポジトリからユーザーを返す)を使用した検証クラスを構築しようとしました。私はこの例を使用しました。これは、どのテストが実行されるかを想像するのはかなり簡単です。MSユニットテストの例

私はこれを回避するためにかなり長い時間を費やしました。ユニットテストとしてどのようにアプローチするのか、どのような例がありますか?私はこれをクラックしたら、私は離れていると思う。

//Arrange 
string email = "[email protected]"; 
string password = "test"; 

//Arrange 
List<Customer> customer = new List<Customer>(); 

customer.Add(new Customer { CustomerId = 1, Email = email, Password = "best", FirstName = "test", LastName = "wods", Sex = true }); 
mockRepos = new Moq.Mock<ICustomerRepository>(); 
mockRepos.Setup(x => x.GetCustomerByPasswordUsername(email, password)).Returns(customer.First()); 
Authenticate auth = new Authenticate(mockRepos.Object); 

//Act 
var result = auth.Login(email, password); 

//Assert 
//this is where I start to become unstuck?????? 

答えて

14

正しい軌道にいるようですが、どのようにテストを進めるのか説明しようとします。

実際のsystem under test(SUT)はAuthenticateクラスです。あなたはそれについて多くのことを話していないので、私は次のことを仮定します:

ICustomerRepositoryのインスタンスを使用して、ユーザー名(電子メール)とパスワードの組み合わせに基づいてユーザーの存在を判断します。

再作成でCustomerのインスタンスが返され、ユーザー名とパスワードの組み合わせが指定されている場合、Loginメソッドはtrueを返します。リポジトリがnullを返した場合、Loginメソッドはfalseを返します。

私はこれらの前提を以下に使用しますが、それらが正しくない場合は、シナリオに合うようにテストを変更することができます。

テスト1:ユーザー名/パスワードの組み合わせが正しい場合、Loginはtrueを返します

public void LoginWillReturnTrueForAValidUsernamePasswordCombination() 
{ 
    string email = "[email protected]"; 
    string password = "test"; 

    //Dummy customer 
    var customer = new Customer(); 

    //Create mock 
    var mockRepos = new Moq.Mock<ICustomerRepository>(); 
    mockRepos.Setup(x => x.GetCustomerByPasswordUsername(
      It.Is<string>(s => s == email), 
      It.Is<string>(s => s == password)) 
     .Returns(customer); 

    var auth = new Authenticate(mockRepos.Object); 

    //Act 
    var result = auth.Login(email, password); 

    //Assert 
    Assert.IsTrue(result); 
} 

It.Isの使用に注意してください。基本的には、模擬テストは、テストで定義された電子メールとパスワードがGetCustomerByPasswordUsernameメソッドに渡されたときにのみダミーの顧客オブジェクトを返すように設定されています。

テスト2:ユーザー名/パスワードの組み合わせが間違っている場合は、Login

public void LoginWillReturnFalseForAnInvalidUsernamePasswordCombination() { string email = "[email protected]"; string password = "test"; //Create mock var mockRepos = new Moq.Mock<ICustomerRepository>(); mockRepos.Setup(x => x.GetCustomerByPasswordUsername( It.Is<string>(s => s == email), It.Is<string>(s => s == password)) .Returns<Customer>(null); var auth = new Authenticate(mockRepos.Object); //Act var result = auth.Login(email, password); //Assert Assert.IsFalse(result); } 

falseを返します暗黙的に上記の試験によってテストが、あなたはさらに一歩進み、そのテストを書きたいこと Loginメソッドが正しいパラメータをリポジトリに渡すことを保証します。セットアップされているメソッドが呼び出されていない場合は、正しく

public void LoginWillInvokeGetCustomerByPasswordUsernameCorrectly() 
{ 
    string email = "[email protected]"; 
    string password = "test"; 

    //Create mock 
    var mockRepos = new Moq.Mock<ICustomerRepository>(); 
    mockRepos.Setup(x => x.GetCustomerByPasswordUsername(
      It.Is<string>(s => s == email), 
      It.Is<string>(s => s == password)) 
     .Returns<Customer>(null) 
     .Verifiable(); 

    var auth = new Authenticate(mockRepos.Object); 

    //Act (ignore result. We are only testing correct invocation) 
    auth.Login(email, password); 

    //Assert 
    mockRepos.Verify(); 
} 

モックのVerifyメソッドは例外をスローログインが呼び出すリポジトリ:

テスト3:このようなテストは、次のようになります。 。

こちらがお役に立てば幸いです。あなたにさらなる質問があるかどうか尋ねるのをためらってください。

+0

こんにちはクラウス。この情報は素晴らしいです。どのような完全に包括的な答え。どうもありがとう! – hoakey

0

SUTがリスナーを追加するAPIを使用するシステムUnder Testを使用した場合、もう少し複雑になることもあります(エグゼキュータとタイマーで同じことを行うことができます) 。

class RealAPIYouSUTUses { 
     public void addListener(XXXListener l); 
} 

class MockAPI implements RealAPIYourSUTUses{ 
     public void addListener(XXXListener l) { 
     this.cachedListener = l; 
     } 
     public XXXListener getListener() { 
     return cachedListener; 
     } 
} 

次に、あなたのユニットテストはlistesnerをテストすることができ、それはシステムとの相互作用だ...

class Test { 
    public void test() { 
     MockAPI mockAPI = new MockAPI(); 
     SUT sut = new SUT(mockAPI); 

     sut.doSomething(); 
     //expect your listener to be added from calling doSomething.... 
     XXXListener l = mockApi.getListener(); 

     //simulate firing an event into your SUT 
     l.fireEvent(new Event("asdf")); 
    } 
} 

すべてこれについて興味深いのは、あなたがExecutor.javaとTimer.javaを模擬することができますし、あなたのテストではエグゼキュータに与えられた実行可能ファイルとTimerTakをTimerに取り込み、システムを確実に動作させるために順番に逆の順序で実行することができます。

私はこの岩のような非同期プログラミングとユニットテストをたくさんしていますので、すべてのクラス間の統合が機能していることを確認できます。

関連する問題