unit testing a class with event and delegate

后端 未结 3 1893
北恋
北恋 2020-12-30 16:20

I am new to testing please help.

I have the following class

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

public class          


        
相关标签:
3条回答
  • 2020-12-30 16:37

    It's probably simplest just to subscribe to the event using an anonymous method:

    [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);
    }
    

    In the second test you might want to validate that the event arguments were as expected too.

    Also note that "invalid" is one word - so your test should be IsValidEntry_WithInvalidTicker. I'd also not bother with the setup - I'd just declare new local variables in each test.

    0 讨论(0)
  • 2020-12-30 16:39

    I would restructure your class to make the RaiseInvalidEntryEvent virtual so it can be mocked in your IsValidEntry_WithInValidTicker and then verified it was called when the ticket was invalid.

    Then I would have another test that verified RaiseInvalidEntryEvent called the anon delegate separately.

    Unit tests should be as atomic as possible, and you would want to verify both of these behaviors in different tests.

    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; }
    }
    

    NOTE: Some OOP evangalists have fits when things are declared public instead of private, basically unit testing and TDD have some requirements that pure OOP is at odds with. I've made RaiseInvalidEntryEvent public for simplicity, but normally I would make this internal and then expose the assembly to the unit test via InternalsVisibleTo. I've been doing TDD for the last 4 years now and rarely use private anymore.

    And the unit tests would quickly be (note, this is using the MSTEST framework from VS2012)

    [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);
        }
    }
    
    0 讨论(0)
  • 2020-12-30 16:49

    Your test should subscribe to the event OnInvalidEntry with a dummy method, call IsValidEntry and check the result.

    0 讨论(0)
提交回复
热议问题