Unit testing a class with an event and a delegate

I am new to testing, please help.

I have the following class

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 + "."); } } 

I have written a test case so far, but am struggling with an event and a delegate as shown below

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

Can someone please help? Thanks..

+4
source share
3 answers

It is probably easiest to subscribe to an 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 can verify that the event arguments were also expected.

Also note that "invalid" is one word, so your test should be IsValidEntry_WithInvalidTicker . I will also not worry about installation - I would just declare new local variables in each test.

+10
source

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

+1
source

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

Then I will have another test that checks RaiseInvalidEntryEvent, which calls the anon delegate separately.

Unit testing should be as atomic as possible, and you would like to test 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 evangelists adapt when things are declared public rather than private, mostly unit testing and TDD have some requirements that pure OOP disagrees with. I made RaiseInvalidEntryEvent publicly available for simplicity, but I usually do it internally and then expose the assembly to the unit test via InternalsVisibleTo. I have been involved in TDD for the past 4 years and rarely use private ones.

And unit tests will be fast (note: this uses the MSTEST structure 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); } } 
+1
source

Source: https://habr.com/ru/post/1479814/


All Articles