2013-05-08 81 views
4

我是新來測試請幫助。單元測試一個類與事件和委託

我有以下類

public delegate void OnInvalidEntryMethod(ITnEntry entry, string message); 

public class EntryValidator 
{ 
    public event OnInvalidEntryMethod OnInvalidEntry; 

    public bool IsValidEntry(ITnEntry entry, string ticker) 
    { 
     if (!IsFieldValid(entry, ticker.Trim().Length.ToString(), "0")) 
      return false; 

     return true; 
    } 

    private bool IsFieldValid(ITnEntry entry, string actual, string invalidValue) 
    { 
     if (actual == invalidValue) 
     { 
      RaiseInvalidEntryEvent(entry); 
      return false; 
     } 

     return true; 
    } 

    private void RaiseInvalidEntryEvent(ITnEntry entry) 
    { 
     if (OnInvalidEntry != null) 
      OnInvalidEntry(entry, "Invalid entry in list: " + entry.List.Name + "."); 
    } 
} 

我迄今所編寫的測試案例,但我與事件和委託掙扎如下圖所示

[TestFixture] 
public class EntryValidatorTests 
{ 
    private EntryValidator _entryValidator; 

    private FakeTnEntry _selectedEntry; 
    private string _ticker; 

    [SetUp] 
    public void Setup() 
    { 
     _entryValidator = new EntryValidator(); 
     _ticker = "BOL"; 
    } 

    private FakeTnEntry MakeEntry(string ticker) 
    { 
     return new FakeTnEntry { Ticker = ticker}; 
    } 

    [Test] 
    public void IsValidEntry_WithValidValues() 
    { 
     _selectedEntry = MakeEntry(_ticker); 

     Assert.IsTrue(_entryValidator.IsValidEntry(_selectedEntry, _selectedEntry.Ticker)); 
    } 

    [Test] 
    public void IsValidEntry_WithInValidTicker() 
    { 
     _selectedEntry = MakeEntry(""); 
     Assert.IsFalse(_entryValidator.IsValidEntry(_selectedEntry, _selectedEntry.Ticker)); 
    } 
}} 

請有人可以幫忙嗎?謝謝..

回答

10

它可能只是簡單的訂閱使用匿名方法事件:

[Test] 
public void IsValidEntry_WithValidValues() 
{ 
    _selectedEntry = MakeEntry(_ticker); 
    _entryValidator.OnInvalidEntry += delegate { 
     Assert.Fail("Shouldn't be called"); 
    }; 

    Assert.IsTrue(_entryValidator.IsValidEntry(_selectedEntry, _selectedEntry.Ticker)); 
}  

[Test] 
public void IsValidEntry_WithInValidTicker() 
{ 
    bool eventRaised = false; 
    _selectedEntry = MakeEntry(""); 
    _entryValidator.OnInvalidEntry += delegate { eventRaised = true; }; 

    Assert.IsFalse(_entryValidator.IsValidEntry(_selectedEntry, _selectedEntry.Ticker)); 
    Assert.IsTrue(eventRaised); 
} 

在您可能要驗證該事件參數分別爲期望太高了第二次測試。

另請注意,「無效」是一個單詞 - 因此您的測試應該是IsValidEntry_WithInvalidTicker。我也不打擾設置 - 我只是在每個測試中聲明新的局部變量。

+0

謝謝你這麼多先生快速回復..會不會我需要的屬性或事件OnInvalidEntry? – user175084 2013-05-08 20:23:46

+0

@ user175084:您已經*獲得了* EntryValidator中的事件。你只是使用匿名方法*訂閱事件。 – 2013-05-08 20:27:25

+0

完美謝謝//是否有文章或樣本或任何類型的材料,我可以閱讀更多關於此? – user175084 2013-05-08 20:36:21

1

您的測試應使用虛擬方法訂閱事件OnInvalidEntry,請致電IsValidEntry並檢查結果。

1

我會重構您的類以使RaiseInvalidEntryEvent虛擬,以便它可以在您的IsValidEntry_WithInValidTicker中模擬,然後驗證它在票證失效時被調用。

然後我會另外一個測試,驗證RaiseInvalidEntryEvent單獨調用anon委託。

單元測試應該儘可能原子化,並且您希望在不同的測試中驗證這兩種行爲。

public delegate void OnInvalidEntryMethod(ITnEntry entry, string message); 

public class EntryValidator 
{ 
    public event OnInvalidEntryMethod OnInvalidEntry; 

    public bool IsValidEntry(ITnEntry entry, string ticker) 
    { 
     if (!IsFieldValid(entry, ticker.Trim().Length.ToString(), "0")) 
      return false; 

     return true; 
    } 

    private bool IsFieldValid(ITnEntry entry, string actual, string invalidValue) 
    { 
     if (actual == invalidValue) 
     { 
      RaiseInvalidEntryEvent(entry); 
      return false; 
     } 

     return true; 
    } 

    public virtual void RaiseInvalidEntryEvent(ITnEntry entry) 
    { 
     if (OnInvalidEntry != null) 
      OnInvalidEntry(entry, "Invalid entry in list: " + entry.List.Name + "."); 
    } 
} 

// Had to reverse engineer the following since they were not available in the question 
public interface ITnEntry 
{ 
    Ticket List { get; set; } 
    string Ticker { get; set; } 
} 

public class TnEntry : ITnEntry 
{ 
    public Ticket List { get; set; } 
    public string Ticker { get; set; } 
} 

public class Ticket 
{ 
    public string Name { get; set; } 
} 

注:某些OOP evangalists有適合當事情聲明爲public,而不是私人的,基本單元測試和TDD有一定的要求,純OOP是與賠率。爲了簡單起見,我公開了RaiseInvalidEntryEvent,但通常我會將這個內部的,然後通過InternalsVisibleTo將程序集暴露給單元測試。我在過去的4年裏一直在做TDD,很少再使用私有的。

而單元測試將很快(注意,這是使用從VS2012的MSTEST框架)

[TestClass] 
public class UnitTest1 
{ 
    #region TestHelpers 

    private ITnEntry MakeEntry(string ticker) 
    { 
     return new TnEntry {Ticker = ticker, List = new Ticket()}; 
    } 

    #endregion 

    [TestMethod] 
    public void IsValidEntry_WithValidValues_ReturnsTrue() 
    { 
     // ARRANGE 
     var target = new EntryValidator(); 
     var selectedEntry = MakeEntry("BOL"); 

     // ACT 
     bool actual = target.IsValidEntry(selectedEntry, selectedEntry.Ticker); 

     // ASSERT 
     Assert.IsTrue(actual); 
    } 

    [TestMethod] 
    public void IsValidEntry_WithInValidTicker_ReturnsFalse() 
    { 
     // ARRANGE 
     var target = new EntryValidator(); 
     var selectedEntry = MakeEntry(""); 

     // ACT 
     bool actual = target.IsValidEntry(selectedEntry, selectedEntry.Ticker); 

     // ASSERT 
     Assert.IsFalse(actual); 
    } 

    [TestMethod]   
    public void IsValidEntry_WithInvalidTicker_RaisesEvent() 
    { 
     // ARRANGE 
     // generate a dynamic mock which will stub all virtual methods 
     var target = Rhino.Mocks.MockRepository.GenerateMock<EntryValidator>(); 
     var selectedEntry = MakeEntry(""); 

     // ACT 
     bool actual = target.IsValidEntry(selectedEntry, selectedEntry.Ticker); 

     // ASSERT 
     // assert that RaiseInvalidEntryEvent was called 
     target.AssertWasCalled(x => x.RaiseInvalidEntryEvent(Arg<ITnEntry>.Is.Anything)); 
    } 

    [TestMethod] 
    public void RaiseInvalidEntryEvent_WithValidHandler_CallsDelegate() 
    { 
     // ARRANGE 
     var target = new EntryValidator(); 
     var selectedEntry = MakeEntry(""); 
     bool delegateCalled = false; 

     // attach a handler to set delegateCalled to true 
     target.OnInvalidEntry += delegate 
     { 
      delegateCalled = true; 
     }; 

     // ACT 
     target.IsValidEntry(selectedEntry, selectedEntry.Ticker); 

     // ASSERT 
     Assert.IsTrue(delegateCalled); 
    } 
}