2013-05-08 52 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); 
    } 
}