unit testing a class with event and delegate - c#

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 the test case so far but am struggling with the event and 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));
}
}}
Please can someone help? Thanks..

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.

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

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

Related

Create wrapper around interface and get method/paramters called

Lets say I have this interface
public interface ITest
{
int Property1 { get; set; }
void Method1();
string GetMethod1();
void MethodWithParam(string str);
}
How can I create a wrapper object around this?
And then capture the methods called or paramters and values accessed etc.
For example:
var myWrapper = GetWrapper<ITest>();
myWrapper.Property1 = 7;
How would I be able to using reflection or whatever to know the following:
Paramter name being called and value being set
var data = myWrapper.GetMethod1("Test");
Get method name of "GetMethod1" along with paramaters and then return a value based on that?
Hope makes sense
Ok so answer quite simple using Castle Core proxy generator:
https://github.com/castleproject/Core
public interface ITest
{
int Property1 { get; set; }
void Method1();
string GetMethod1();
void MethodWithParam(string str);
}
public static class Wrapper
{
private class MethodInterceptor : IInterceptor
{
Action<IInvocation> OnIntercept;
public MethodInterceptor(Action<IInvocation> OnIntercept)
{
this.OnIntercept = OnIntercept;
}
public void Intercept(IInvocation invocation)
{
OnIntercept?.Invoke(invocation);
}
}
private static void CallAPI(IInvocation invocation)
{
var methodName = invocation.Method.Name;
var valuespassed = invocation.Arguments;
var retType = invocation.Method.ReturnType.FullName;
//DO API THINGS NOW
}
public static T Get<T>()
{
ProxyGenerator generator = new ProxyGenerator();
var interceptor = new MethodInterceptor(CallAPI);
var c = generator.CreateInterfaceProxyWithoutTarget<ITest>(interceptor);
return (T)c;
}
}
public class Test123
{
public void Test()
{
var c = Wrapper.Get<ITest>();
c.Property1 = 7;
var propval = c.Property1;
}
}
Any action on c calls the intercept function where can get everything from method name being called to arguments passed.

Is there any solution to handle dataType for TestCaseSource ? [Nunit Framework]

Based on https://gigi.nullneuron.net/gigilabs/data-driven-tests-with-nunit/ website. I have try to create a simple testcase which prepare for read data in the future. But I have no idea how to handle Argument and use it properly
I have try to set as a object, but i think this might not be a correct solution
[TestCaseSource("GetDataString")]
public void TestMethod2(object configs)
{
}
Here is source code
namespace SAP
{
[TestFixture]
public class Scenario1
{
// This one Give System.ArgumentException
[TestCaseSource("GetDataString")]
public void TestMethod(List<Config> configs)
{
Console.WriteLine("Config " + configs);
}
// This one can handle an Exception
[TestCaseSource("GetDataString")]
public void TestMethod2(object configs)
{
}
public static List<Config> GetDataString()
{
var datas = new List<Config>();
datas.Add(new Config("Nick", "Coldson"));
return datas;
}
}
public class Config
{
public string NickName { get; set; }
public string Name { get; set; }
public Config(string nickname, string name)
{
NickName = nickname;
Name = name;
}
}
}
Here is error msg
System.ArgumentException : Object of type 'SAP.Config' cannot be
converted to type 'System.Collections.Generic.List`1[SAP.Config]'.
The testcasesource has slightly different definition pattern. Assuming you use nunit 3 it should be:
[TestCaseSource(typeof(MyTestData), nameof(GetDataString))]
public void TestMethod2(List<Config> configs)
{
...
}
public class MyTestData
{
public static IEnumerable GetDataString()
{
var datas = new List<Config>();
datas.Add(new Config("Nick", "Coldson"));
return new TestCaseData(datas);
}
}
For more info, check the documentation:
https://github.com/nunit/docs/wiki/TestCaseData
Your GetDataString returns a List<Config>.
Meaning, your test method with a [TestCaseSource("GetDataString")] will be executed as many times as many items the list has and your method must match the item type.
//// This one throws System.ArgumentException
//[TestCaseSource("GetDataString")]
//public void TestMethod(List<Config> configs)
//{
// Console.WriteLine("Config " + configs);
//}
// This one is ok
[TestCaseSource("GetDataString")]
public void TestMethod(Config config)
{
Console.WriteLine(config);
}
If you need to get List<Config> instances in your test, then your source must return some collection containing list items.

Raising complex event using Moq in C#

The following code should be self explanetory: we have an adaptor, who consumes events from the transport (layer), which holds the MessageRegistrar (object type because we can't tell it's type, and basically because this is legacy code :-) ). The transport layer have a concrete which have an event.
I want to test a case where the event is triggered, so..
After hours of trying to figure why it won't pass, I present the following challenge:
[TestFixture]
public class AdaptorTests
{
public delegate void TracksEventHandler(object sender, List<int> trklst);
public class MyEventHolder
{
public virtual event TracksEventHandler EventName;
}
public interface ITransport
{
object MessageRegistrar { get; }
}
public class MyTransport : ITransport
{
private readonly MyEventHolder m_eventHolder;
public MyTransport(MyEventHolder eventHolder)
{
m_eventHolder = eventHolder;
}
public virtual object MessageRegistrar
{
get { return m_eventHolder; }
}
}
public class MyAdaptor
{
private readonly ITransport m_transport;
public MyAdaptor(ITransport transport)
{
EventTriggered = false;
m_transport = transport;
}
public void Connect()
{
MyEventHolder eventHolder = m_transport.MessageRegistrar as MyEventHolder;
if (eventHolder != null)
eventHolder.EventName += EventHolderOnEventName;
}
private void EventHolderOnEventName(object sender, List<int> trklst)
{
EventTriggered = true;
}
public bool EventTriggered { get; private set; }
}
[Test]
public void test1()
{
Mock<MyEventHolder> eventHolderMock = new Mock<MyEventHolder> {CallBase = true};
Mock<MyTransport> transportMock = new Mock<MyTransport>(eventHolderMock.Object) {CallBase = true};
MyAdaptor adaptor = new MyAdaptor(transportMock.Object);
adaptor.Connect();
MyEventHolder eventHolder = transportMock.Object.MessageRegistrar as MyEventHolder;
Mock.Get(eventHolder).Raise(eh => eh.EventName += null, new List<int>());
Assert.IsTrue(adaptor.EventTriggered);
}
[Test]
public void test2()
{
Mock<MyEventHolder> eventHolderMock = new Mock<MyEventHolder> { CallBase = true };
Mock<MyTransport> transportMock = new Mock<MyTransport>(eventHolderMock.Object) { CallBase = true };
MyAdaptor adaptor = new MyAdaptor(transportMock.Object);
adaptor.Connect();
MyEventHolder eventHolder = transportMock.Object.MessageRegistrar as MyEventHolder;
Mock.Get(eventHolder).Raise(eh => eh.EventName += null, null, new List<int>());
Assert.IsTrue(adaptor.EventTriggered);
}
}
My question is: why wont the test (at least one of them) pass?
EDIT #151217-0822 Addded 'adaptor.Connect()' to the original post (still won't fix the issue).
WORKAROUND
Credits to #Patrick Quirk: Thanks!!
For those encountering the same issue: after I understood what Patrick-Quirk detected, and trying couple of failed workarounds, I've ended up adding the following verified fix: 'eventHolder.FireEventNameForTestings(new List());':
public class MyEventHolder
{
public virtual event TracksEventHandler EventName;
public virtual void FireEventNameForTestings(List<int> trklst)
{
TracksEventHandler handler = EventName;
if (handler != null)
handler(this, trklst);
}
}
[Test]
public void test3()
{
Mock<MyEventHolder> eventHolderMock = new Mock<MyEventHolder> { CallBase = true };
Mock<MyTransport> transportMock = new Mock<MyTransport>(eventHolderMock.Object) { CallBase = true };
MyAdaptor adaptor = new MyAdaptor(transportMock.Object);
adaptor.Connect();
MyEventHolder eventHolder = transportMock.Object.MessageRegistrar as MyEventHolder;
eventHolder.FireEventNameForTestings(new List<int>());
Assert.IsTrue(adaptor.EventTriggered);
}
HTH..
It seems that CallBase and Raise() have an unexpected (to me) interaction.
When you are attaching an event handler to a virtual event on a mock, you go through this code in Moq:
if (invocation.Method.IsEventAttach())
{
var delegateInstance = (Delegate)invocation.Arguments[0];
// TODO: validate we can get the event?
var eventInfo = this.GetEventFromName(invocation.Method.Name.Substring(4));
if (ctx.Mock.CallBase && !eventInfo.DeclaringType.IsInterface)
{
invocation.InvokeBase();
}
else if (delegateInstance != null)
{
ctx.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]);
}
return InterceptionAction.Stop;
}
You can see that if CallBase is true, then it will add your handler to the concrete object's event (via invocation.InvokeBase()). If CallBase is false, it will add it to an invocation list on the mock (via AddEventHandler). Now let's look at the code for Raise(), which gets the event object from the Expression and then calls DoRaise():
internal void DoRaise(EventInfo ev, EventArgs args)
{
// ... parameter validation
foreach (var del in this.Interceptor.InterceptionContext.GetInvocationList(ev).ToArray())
{
del.InvokePreserveStack(this.Object, args);
}
}
See the call to GetInvocationList()? That retrieves the invocation list from the mock that I mentioned above. This code never invokes the actual event on the base object.
So, it seems there's no way to raise an event on a mocked object where CallBase is set to true.
The only workaround I see, if you require CallBase being true, is to add a method to your concrete MyEventHolder to trigger your event. Obviously what you posted is a simplified example so I can't give you more guidance than that, but hopefully I've shown you why what you have does not work.

Issue with Unit Testing Model View Presenter

I am creating an application in ASP.NET web form with MVP pattern. I am getting some issues working with TDD. I have created two test, one is working fine but when a second test is executed it throws an error.
Below is my declared View
public interface IAddUpdateView : IView
{
string Type { get; set; }
string PageTitle { set; }
string Details { get; set; }
bool Active { get; set; }
}
Presenter
// BasePresenter is an abstract class contains abstract method with name Initialize()
public class MyPresenter: BasePresenter<IAddUpdateView >
{
private readonly IDatabaseLayer _databaselayer;
public MyPresenter(IAddUpdateView view, IDatabaseLayer databaseLayer) : base(view)
{
_databaselayer = databaseLayer;
}
public override void Initialize()
{ }
public void Initialize(string str)
{
string[] str1=Misc.DecryptURL(str);
View.Type = str1[0].ToString(); // ERROR LINE
if (View.Type.ToLower().Trim() == "add")
{
View.PageTitle = "Add New Task";
}
else if (View.Type.ToLower().Trim() == "edit")
{
}
}
}
Now I am working on creating unit test mocking the Presenter class to test the dependencies using Rhino mocks.
That's my test class with just two test methods. These test methods test when loading a View it calls appropriate Page Type.
When ADD type is called, it get the View.Type as "add" and when Edit type is called, it verifies for the specific object that is loaded.
[TestFixture]
public class MyPresenterTest
{
private IAddUpdateView _view;
private MyPresernter _controller;
[SetUp]
public void SetUp()
{
_view = MockRepository.GenerateMock<IAddUpdateView >();
_controller = new MyPresernter (_view, MockDataLayer());
}
[TearDown]
public void TearDown() { _controller = null; _view = null; }
// TEST 1
[Test]
public void When_Loading_for_Add_View_Panel_Return_Type_Add()
{
// Arrange
_view.Stub(x => x.Type).PropertyBehavior();
//Act
_controller.Initialize(GetURLWithAddValue());
// GetURLWithAddValue: This method get the URL with querystring contains value as "add"
//Assert
Assert.AreEqual("add",_view.Type);
}
TEST 2
// When this test method is run, It has the Type="edit", but in my
presenter View.Type (see LINE ERROR), my Type is null even I
assigned the values.
[Test]
public void When_Loading_for_Edit_View_Panel_Load_Correct_Object()
{
// Arrange
_view.Stub(x =>x.TaskDetails).PropertyBehavior();
//Act
Task o=new Task(){ TaskId=6, TASK_NAME="Task 6"};
_controller.Initialize(GetURLWithEditValue(o));
//Assert
Assert.AreEqual(o.TASK_NAME, _view.TaskDetails);
}
private static IDatabaseLayer MockDataLayer()
{
IDatabaseLayer obj = MockRepository.GenerateMock<IDatabaseLayer>();
MockTaskDataLayer a = new MockTaskDataLayer();
obj.Stub(x => x.GetList());
return obj;
}
}
Can someone guide me why Test 1 get passed and when Test 2 is executed, after assigning a value in View.Type (see LINE ERROR in MyPresenter class) it's still null??
Thanks,

nunit testing of method which calls other method

Am very new to nunit.below is the business unit code
public enum HighlightType
{
IP,
Item,
Address
}
public class UniformGridHighlighting
{
public static event HighlightingChangedDelegate HighlightingChanged;
private static List<string> _highlightedIPs = new List<string>();
private static List<long> _highlightedItems = new List<long>();
private static ContactInfoType _highlightedAddress;
public static void ClearIPHighlighting()
{
_highlightedIPs.Clear();
OnHighlightingChanged(HighlightType.IP);
}
private static void OnHighlightingChanged(HighlightType type)
{
if (HighlightingChanged != null)
{
HighlightingChanged(type);
}
}
}
I need to write unit test cases for ClearIPHighlighting. How do i proceed.
[Test(Description = "to ")]
public void ClearIPHighlightingTets()
{
UniformGridHighlighting.ClearIPHighlighting();
//How to call method
}
Given the current setup you can only test that the event is triggered.
[Test()]
public void ThatTheEventIsTriggeredWhenTheListIsCleared()
{
// Arrange
bool eventTriggered = false;
UniformGridHighlighting.HighlightingChanged += _ => { eventTriggered= true; };
//Act
UniformGridHighlighting.ClearIPHighlighting();
//Assert:
Assert.IsTrue(eventTriggered);
}
And that it's of the right type
[Test(Description = "to ")]
public void ThatTheEventIsTriggeredWithTheIPArgumentWhenTheIPListIsCleared()
{
// Arrange
HighlightType? type = null;
UniformGridHighlighting.HighlightingChanged += x => { type = x; };
//Act
UniformGridHighlighting.ClearIPHighlighting();
//Assert:
Assert.AreEqual(s, HighlightType.IP);
}
To test that your previous highlight was removed is going to be harder:
[Test]
public void ThatTheIpIsNotHighlightedIfTheListWasCleared()
{
UniformGridHighlighting.HighlightIP("1.1.1.1");
//Act
UniformGridHighlighting.ClearIPHighlighting();
UniformGridHighlighting.Highlihst(Grid);
//Assert:
//Go through the grid to figure out that the IP was not highlighted. The below is a total guess:
bool wasHighlighted = Grid.Rows.Any(row => row.Cells.Any(Cell.Highlighted));
Assert.Isfalse(wasHighlighted);
}

Categories