How to test a delegated method - c#

I have a simple method in a class that is responsible to register a FileSystemWatcher given a certain path in appconfig.xml:
public void ListenPath(string path){
//path validation code
//...
FileSystemWatcher objFileWatcher = new FileSystemWatcher();
objFileWatcher.Path = path;
objFileWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
objFileWatcher.Filter = "*.txt";
objFileWatcher.Created += new FileSystemEventHandler(ProcessInput);
objFileWatcher.EnableRaisingEvents = true;
}
In my unit test I have to assert:
1) Giving a wrong or null path it should raise an PathNotFoundException
2) That ProcessInput method was correctly registered to listen to "path" when files are created.
How can I perform the unit test for item 2?
thanks a lot

Registering a callback on an event is simply populating a variable. It's more or less adding a callback to a list of callbacks. I don't generally validate incidental stuff like population of a list, unless data population is the whole point of the class (like if the class represented a custom data structure).
You can instead validate that ProcessInput gets called when you modify the specified file. A couple ways to go about this:
Test side-effects of ProcessInput, e.g. it populated some other structure or property in your program
Separate out the ProcessInput method into another class or interface. Take a reference to this type as an argument to ListPath, or the constructor for the class. Then mock that type
Mock object example:
public interface IInputProcessor
{
void ProcessInput(Object sender, FileSystemEventArgs e);
}
public class ClassUnderTest
{
public ClassUnderTest(IInputProcessor inputProcessor)
{
this.inputProcessor = inputProcessor;
}
public void ListenPath(string path){
// Your existing code ...
objFileWatcher.Created +=
new FileSystemEventHandler(inputProcessor.ProcessInput);
// ...
}
private IInputProcessor inputProcessor;
}
public class MockInputParser : IInputProcessor
{
public MockInputParser()
{
this.Calls = new List<ProcessInputCall>();
}
public void ProcessInput(Object sender, FileSystemEventArgs args)
{
Calls.Add(new ProcessInputCall() { Sender = sender, Args = args });
}
public List<ProcessInputCall> Calls { get; set; }
}
public class ProcessInputCall
{
public Object Sender;
public FileSystemEventArgs Args;
}
[Test]
public void Test()
{
const string somePath = "SomePath.txt";
var mockInputParser = new MockInputParser();
var classUnderTest = new ClassUnderTest(mockInputParser);
classUnderTest.ListenPath(somePath);
// Todo: Write to file at "somePath"
Assert.AreEqual(1, mockInputParser.Calls.Count);
// Todo: Assert other args
}

If the FileSystemWatcher is something you have access to, you can set it up so that you can mock the firing of the Created event. But I suspect it's not, which means you're getting to the point here where true "unit testing" isn't very easy.
You could try using an isolator like TypeMock or maybe Moles to simulate the firing of the Created event. But the easiest thing might be to actually write a test that creates a file at the given path, and ensure that the ProcessInput method gets called when that happens.
Because you haven't shown the definition or any other code around ProcessInput itself, I don't know the best way to go about ensuring that it got called.

You could split your method into two: the first method simply instantiates, configures and returns an instance of the FileSystemWatcher. You could then easily test on the returned result object. A second method could take it as argument and simply enable rising events on it.

Related

Call this.StateHasChanged in EventHandler

I have the following problem.
I created an event and subscribe to it, now I want that the UI changes when the Event triggers.
using System;
using MintWebApp.Data;
using MintWebApp.Models;
using Microsoft.AspNetCore.Components;
namespace WebApp.UI.Core
{
public partial class AppHeader
{
public string status { get; set; }
[Inject]
public StateService state { get; set; }
EventHandler<string> onStatusChanged= (sender, eventArgs) => {
//Here i get the error, I can't access this and status
status = eventArgs;
this.StateHasChanged();
Console.WriteLine(eventArgs.PatientName);
};
protected override void OnInitialized() => state.StatusHandler += onStatusChanged;
}
}
I get this Error
A field initializer cannot reference the non-static field, method, or property 'AppHeader.patientContext'
Keyword 'this' is not available in the current context
How can I subscripe to an event and update the UI
This needs to be approached a bit differently as the EventHandler<T> type doesn't work as expected here. (At Least not for me)
First off, for the EventArgs, remember that this is a type, so you can't assign them to the Status property (which you have as a string) without a cast. The way to do this is to define your own arguments type that derives from EventArgs, something like this:
public class PatientEventArgs: EventArgs
{
public string PatientName {get; set;}
public string StatusValue {get; set;}
}
Next for the handler method that you need to use, set it up as an async method. I found that the async was important so you can use an InvokeAsync farther down and avoid an exception when the thread and dispatcher don't agree, as in other windows open or other users signed in elsewhere, through this post:
Discussion on thread vs. Synchronization Context
private async void OnStatusChanged(object sender, EventArgs e) {
// Make sure the args are the type you are expecting
if(e.GetType() == typeof(PatientEventArgs))
//Cast to the correct Args type to access properties
var patientStatus = e as PatientEvendArgs;
status = patientStatus.StatusValue;
Console.Writeline(patientStatus.PatientName);
/* Use InvokeAsync method with await to make sure
StateHasChanged runs correctly here without interfering with another
thread (open window or other users) */
await InvokeAsync(() => StateHasChanged());
}
Next, and important to your scenario, you will hit a wall with the Partial Class declaration as you have it since you need to implement IDisposable to clean up after yourself as the component tears down. Instead, use an inheritance structure as follows and use the OnInitialized and Dispose overrides
AppHeader.razor.cs
public class AppHeaderBase : OwningComponentBase
{
// OnStatusChanged method as described above
protected override void OnInitialized() //Can use the Async version as well
{
// Unsubscribe once to make sure you are only connected once
// Prevents event propogation
// If this component is not subscribed this doesn't do anything
state.StatusHandler -= onStatusChanged;
// Subscribe to the event
state.StatusHandler += onStatusChanged;
}
protected override void Dispose(bool disposing)
{
// Unsubscribe on teardown, prevent event propogation and memory leaks
state.StatusHandler -= onStatusChanged;
}
}
This takes advantage of some built in Blazor features in OwningComponentBase and includes a Dispose Method, while doing a much better job of managing your Dependency Injection for you.
Further reading HERE (Note that I didn't go too deep on this for this example as it's using a singleton, but worth the reading to understand DI lifetimes in Blazor)
And then in your AppHeader.razor
....
#inherits AppHeaderBase
....
Now when you use the event handler in the StateService from somewhere else, build up a new PatientEventArgs type with the values you need to pass:
var newArgs = new PatientEventArgs(){
PatientName = "SomeName",
StatusValue = "SomeStatus"
};
And pass it in as needed in your code:
state.OnStatusChanged(this, newArgs);
Or direct from Razor syntax:
<button #onclick="#(() => state.OnStatusChanged(this, new PatientEventArgs(){ PatientName = "SomeName", StatusValue = "SomeStatus"})">Sender Button</button>
This should multicast your event out as needed, and all subscribers should pick it up and update.
Here is a quick working demo if needed, adapted from another version of this I've been working on.

Unit testing methods in the Presenter, MVP

Im trying to test a method which composes a collection of controls. It calls two methods:
Copies the original collection.
Sorts the new collection.
Ideally id like to be able to pass in a collection and test to see thats it sorts it correctly. Id also like to verify that method 1) is called twice, see below attempt based on the following:
Example using RhinoMock
The following test is producing errors when i try to create an instance of MainPresenter. General jist of the errors are "Can not convert from Moq.Mock to "FrazerMann.CsvImporter.UserInterface.IMainForm. + a similar one for IFileDialog.
[Test]
public void ComposeCollectionOfControls_CallSequence_4Calls()
{
var main = new Mock<IMainForm>();
var dialog = new Mock<IFileDialog>();
var temp = new Mock<IMainPresenter>();
temp.Setup(s => s.PopulateLists<Control>(It.IsAny<TableLayoutPanel>(), It.IsAny<List<Control>>()));
var testObject = new MainPresenter(main.Object, dialog.Object);
testObject.ComposeCollectionOfControls(It.IsAny<object>(), It.IsAny<EventArgs>());
temp.Verify(v => v.PopulateLists<Control>(It.IsAny<TableLayoutPanel>(), It.IsAny<List<Control>>()), Times.Once());
}
I would like to test the ComposeCollectionOfControls to ensure PopulateList() is called twice.
public interface IMainPresenter
{
void PopulateLists<T>(TableLayoutPanel userInputs, List<T> container) where T : Control;
int SortList<T>(T control1, T control2) where T : Control;
}
public class MainPresenter:IMainPresenter
{
UserInputEntity inputs;
IFileDialog _dialog;
IMainForm _view;
public MainPresenter(IMainForm view, IFileDialog dialog)
{
_view = view;
_dialog = dialog;
view.ComposeCollectionOfControls += ComposeCollectionOfControls;
view.SelectCsvFilePath += SelectCsvFilePath;
view.SelectErrorLogFilePath += SelectErrorLogFilePath;
view.DataVerification += DataVerification;
}
public void ComposeCollectionOfControls(object sender, EventArgs e)
{
PopulateLists<TextBox>(_view.ColumnNameCtrls, _view.SortedColumnNameCtrls);
_view.SortedColumnNameCtrls.Sort(SortList<TextBox>);
PopulateLists<ComboBox>(_view.ColumnDataTypeCtrls, _view.SortedColumnDataTypeCtrls);
_view.SortedColumnDataTypeCtrls.Sort(SortList<ComboBox>);
}
}
Could someone please give me some pointers as to how this should be done?
The error you are seeing is because your are passing the mock class itself (which is of type Moq.Mock) rather than the mocked object that Moq creates for you.
Instead of:
var testObject = new MainPresenter(main, dialog);
you need:
var testObject = new MainPresenter(main.Object, dialog.Object);
As an aside, it is usually considered bad practice to explicitly verify things like the number of calls made on a particular method. This leads to a tight coupling between your tests and a particular implementation, and consequently brittle tests.
By testing how many times you call a method you will often find a test failing after you refactor some code when the end result of the code is still correct.
It is much better to test the final state of the objects involved, and make your tests ignorant of how that state was reached.

Verifying event handler code executed

I have code very similar to this but cannot work out how I test whether an event handler occured.
public class MyClass : MyAbstractClass
{
IFileSystem FileSystem;
public MyClass(IFileSystem myFileSys)
{
FileSystem = myFileSys;
FileSystem.EventHit += new EventHandler(FileSystem_EventHit);
}
public void FileSystem_EventHit(object sender, EventArgs e)
{
//Testing base.OnOutput is not possible which I wont go into
base.OnOutput("EventHit");
}
}
Testing code is here:
[Test]
public void DoSomething_WhenCalled_EventFired()
{
var mock = new Moq.Mock<IFileSystem>();
MyClass plugin = new MyClass (mock.Object);
mock.Object.DoSomething();
mock.Raise(x => x.EventHit += null, new EventArgs());
//Verify/Assert that MyClass handled and did something in the event handler
}
The simplest way I can think of is to just add your own handler in the test method, which should suffice I would think?
[Test]
public void DoSomething_WhenCalled_EventFired()
{
var mock = new Moq.Mock<IFileSystem>();
bool isHit = false;
mock.EventHit += (s, e) =>
{
isHit = true;
};
MyClass plugin = new MyClass (mock.Object);
mock.Object.DoSomething();
mock.Raise(x => x.EventHit += null, new EventArgs());
Assert.IsTrue(isHit);
}
As verifying something in the event handler would mean trying to test legacy code the option I went with was to test that the event fired from within the concrete type and not a mock.
[Test]
public void DoSomething_WhenCalled_EventFired()
{
FileSystem fs = new FileSystem(mock.Object, timerMock.Object);
bool WasItHit = false;
fs.EventHit += delegate { WasItHit = true; };
fs.DoSomething(); //This should call the event
Assert.IsTrue(WasItHit);
}
You need to inject a mock of whatever gets called as a result of the event handler invocation and verify it. Your comment says you can't test base base.OnOutput, but it seems to me that is exactly what you need to do.
Basically testing of a fact that method was called is not a valid test case, you should test a logic/behaviour behind a method. Obviously with a given event handler there is nothing to test, this is why a task looks not trivial.
Try out formulate in few words what are you trying to test, which test case. For instance
MyClass switches a state into the State==Hit whilst
FileSystem.EventHit event.
To do that you probably need a flag in MyClass indicating that event occured. I know, this will be just for purpose of running a test but sometimes is good to have something like that.

How can I test that an event contains an event handler?

I want to test that class A's RegisterEventHandlers() method registers one of its methods as an EventHandler for an event on class B. How can I do that? I'm using moq, if that matters.
I don't think there's a way to inspect the event handler delegate from outside the class (please correct me if I'm wrong).
It'd be nice if I could trigger the event and then assert that my callback was called, but if I mock the interface of the A class (and set up an expectation for the callback) then I lose the implementation of RegisterEventHandlers(), which is the method I'm testing in the first place.
Mocking the B class's event would be the best option, but I don't see what method I'd have to intercept to do this. Is there some way to set up a mock for an event, and intercept the += method call?
Is there a clean solution to this?
You can get the invocation list for an event outside the class declaring the event - but it involves reflection. Below is a code example showing how you can determine which methods (on target instance a) are added to the event b.TheEvent after a call to a.RegisterEventHandlers(). Paste the code below in a code file and add to a form or console project: Test test = new Test(); test.Run();
using System;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
public class A
{
B m_b = new B();
public void RegisterEventHandlers()
{
m_b.TheEvent += new EventHandler(Handler_TheEvent);
m_b.TheEvent += new EventHandler(AnotherHandler_TheEvent);
}
public A()
{
m_b.TheEvent += new EventHandler(InitialHandler_TheEvent);
}
void InitialHandler_TheEvent(object sender, EventArgs e)
{ }
void Handler_TheEvent(object sender, EventArgs e)
{ }
void AnotherHandler_TheEvent(object sender, EventArgs e)
{ }
}
public class B
{
public event EventHandler TheEvent;
//{
// //Note that if we declared TheEvent without the add/remove methods, the
// //following would still generated internally and the underlying member
// //(here m_theEvent) can be accessed via Reflection. The automatically
// //generated version has a private field with the same name as the event
// //(i.e. "TheEvent")
// add { m_theEvent += value; }
// remove { m_theEvent -= value; }
//}
//EventHandler m_theEvent; //"TheEvent" if we don't implement add/remove
//The following shows how the event can be invoked using the underlying multicast delegate.
//We use this knowledge when invoking via reflection (of course, normally we just write
//if (TheEvent != null) TheEvent(this, EventArgs.Empty)
public void ExampleInvokeTheEvent()
{
Delegate[] dels = TheEvent.GetInvocationList();
foreach (Delegate del in dels)
{
MethodInfo method = del.Method;
//This does the same as ThisEvent(this, EventArgs.Empty) for a single registered target
method.Invoke(this, new object[] { EventArgs.Empty });
}
}
}
public class Test
{
List<Delegate> FindRegisteredDelegates(A instanceRegisteringEvents, B instanceWithEventHandler, string sEventName)
{
A a = instanceRegisteringEvents;
B b = instanceWithEventHandler;
//Lets assume that we know that we are looking for a private instance field with name sEventName ("TheEvent"),
//i.e the event handler does not implement add/remove.
//(otherwise we would need more reflection to determine what we are looking for)
BindingFlags filter = BindingFlags.Instance | BindingFlags.NonPublic;
//Lets assume that TheEvent does not implement the add and remove methods, in which case
//the name of the relevant field is just the same as the event itself
string sName = sEventName; //("TheEvent")
FieldInfo fieldTheEvent = b.GetType().GetField(sName, filter);
//The field that we get has type EventHandler and can be invoked as in ExampleInvokeTheEvent
EventHandler eh = (EventHandler)fieldTheEvent.GetValue(b);
//If the event handler is null then nobody has registered with it yet (just return an empty list)
if (eh == null) return new List<Delegate>();
List<Delegate> dels = new List<Delegate>(eh.GetInvocationList());
//Only return those elements in the invokation list whose target is a.
return dels.FindAll(delegate(Delegate del) { return Object.ReferenceEquals(del.Target, a); });
}
public void Run()
{
A a = new A();
//We would need to check the set of delegates returned before we call this
//Lets assume we know how to find the all instances of B that A has registered with
//For know, lets assume there is just one in the field m_b of A.
FieldInfo fieldB = a.GetType().GetField("m_b", BindingFlags.Instance | BindingFlags.NonPublic);
B b = (B)fieldB.GetValue(a);
//Now we can find out how many times a.RegisterEventHandlers is registered with b
List<Delegate> delsBefore = FindRegisteredDelegates(a, b, "TheEvent");
a.RegisterEventHandlers();
List<Delegate> delsAfter = FindRegisteredDelegates(a, b, "TheEvent");
List<Delegate> delsAdded = new List<Delegate>();
foreach (Delegate delAfter in delsAfter)
{
bool inBefore = false;
foreach (Delegate delBefore in delsBefore)
{
if ((delBefore.Method == delAfter.Method)
&& (Object.ReferenceEquals(delBefore.Target, delAfter.Target)))
{
//NOTE: The check for Object.ReferenceEquals(delBefore.Target, delAfter.Target) above is not necessary
// here since we defined FindRegisteredDelegates to only return those for which .Taget == a)
inBefore = true;
break;
}
}
if (!inBefore) delsAdded.Add(delAfter);
}
Debug.WriteLine("Handlers added to b.TheEvent in a.RegisterEventHandlers:");
foreach (Delegate del in delsAdded)
{
Debug.WriteLine(del.Method.Name);
}
}
}
When mocking B, declare the EventHandler like this:
public class B : IB
{
public int EventsRegistered;
public event EventHandler Junk
{
add
{
this.EventsRegistered++;
}
remove
{
this.EventsRegistered--;
}
}
}
I'm not certain that moq allows this, but I'm sure you can create your own mock class.
You are correct that you cannot access the event delegates from outside the class, this is a limitation within the C# language.
The most straight-forward approach to test this, would be to mock class B and then raise it's event and then observe the side-effects of the event being raised. This is slightly different than what you're looking for but it demonstrates class's A behavior rather than its implementation (this is what your tests should strive to do).
In order for this to work, class B must be mockable and the event that it exposes must also be virtual. Moq can't intercept events if they're not declared as virtual. Alternatively, if B is an interface be sure that the event is declared there.
public interface IEventProvider
{
event EventHandler OnEvent;
}
public class Example
{
public Example(IEventProvider e)
{
e.OnEvent += PerformWork;
}
private void PerformWork(object sender, EventArgs e)
{
// perform work
// event has an impact on this class that can be observed
// from the outside. this is just an example...
VisibleSideEffect = true;
}
public bool VisibleSideEffect
{
get; set;
}
}
[TestClass]
public class ExampleFixture
{
[TestMethod]
public void DemonstrateThatTheClassRespondsToEvents()
{
var eventProvider = new Mock<IEventProvider>().Object;
var subject = new Example(eventProvider.Object);
Mock.Get(eventProvider)
.Raise( e => e.OnEvent += null, EventArgs.Empty);
Assert.IsTrue( subject.VisibleSideEffect,
"the visible side effect of the event was not raised.");
}
}
If you really need to test the implementation, there are other mechanisms available, such as a hand-rolled Test Spy / Test Double, or reflection-based strategy to get the delegate list. My hope is that you should be more concerned with class A's event handling logic than its event handler assignment. After all, if class A doesn't respond to the event and do something with it, the assignment shouldn't matter.
I don't know much about unit testing, but perhaps this link can give you some ideas. Note that the virtual keyword also works there.
I don't think moq has that capability - if you're prepared to purchase a tool I suggest you use Typemock Isolator that can verify that any method on an object was called - including event handler - have a look at link.

Rhino Mocks, Interfaces and properties

I have a class that has a property that I need to stub. I can't pass it as part of the constructor because the object constructing it does not know the parameters of the constructor.
When running unit tests, I want to be able to have the property be created as a stub.
This is what I have tried, but it does not work:
private DeviceMediator deviceMediator;
private IDeviceControlForm deviceControlForm;
private IDataAccess data;
private ICallMonitor callMonitor;
// Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
// This line works fine
deviceControlForm = MockRepository.GenerateStub<IDeviceControlForm>();
// This line works fine
data = MockRepository.GenerateStub<IDataAccess>();
// This has to be an ICallMonitor. If I try to make it a
// CallMonitor then it fails.
callMonitor = (CallMonitor)
MockRepository.GenerateStub<ICallMonitor>();
// This line does not compile. Because it wants to
// return a CallMonitor not an ICallMonitor.
Expect.Call(new CallMonitor(null)).Return(callMonitor);
// This is the class that has the CallMonitor (called callMonitor).
deviceMediator = new DeviceMediator(deviceControlForm, data);
}
Is there anyway to catch the constructor call to CallMonitor and make it actually be a stub?
In case it is relevant, here is the related code in DeviceMediator:
private IDeviceControlForm form;
private readonly IDataAccess data;
public ICallMonitor CallMonitor { get; set; }
public DeviceMediator(IDeviceControlForm form, IDataAccess data)
{
this.form = form;
this.data = data;
CallMonitor = new CallMonitor(OnIncomingCall);
}
Thanks in advance for any help.
Since the CallMonitor property is writable, you can just overwrite the original value with a mock instance (your DeviceMediator actually implements the Property Injection design pattern).
So you can write a test like this:
[TestMethod]
public void MyTest()
{
var deviceControlForm = MockRepository.GenerateStub<IDeviceControlForm>();
var data = MockRepository.GenerateStub<IDataAccess>();
var mockCallMonitor = MockRepository.GenerateStub<ICallMonitor>();
var deviceMediator = new DeviceMediator(deviceControlForm, data);
deviceMediator.CallMonitor = mockCallMonitor;
// The rest of the test...
}
Firstly you can stub/mock classes directly in RhinoMock so if you want an actual CallMonitor stub rather than ICallMonitor you can, and this will overcome the casting issue in your code. The reason the cast fails is that RhinoMock creates a 'dynamic proxy' object which is not CallMonitor.
Secondly you cannot mock constructor calls, and most importantly there is no way to mock the call to new CallMonitor in the DeviceMediator constructor since there is no way to inject an instance.
The usual way to do what you want would be to change the DeviceMediator constructor to this:
public DeviceMediator(IDeviceControlForm form, IDataAccess data, ICallMonitor callMonitor) { ... }
Then your test can inject a stub/mock instance of this interface into the constructor.
EDIT: If you really can't inject an instance into the constructor then you have a few options:
Create a factory which you can stub:
public class CallMonitorFactory
{
public virtual CallMonitor CreateMonitor(args...) { }
}
public DeviceMediator(IDeviceControlForm form, IDataAccess data, CallMonitorFactory factory)
{
this.form = form;
this.data = data;
CallMonitor = factory.CreateMonitor(OnIncomingCall);
}
Add a protected factory method on DeviceMediator which returns a CallMonitor. You will then have to manually create a sub-class of DeviceMediator in your test so you can return the mock CallMonitor object.
Move the constructor argument for CallMonitor into a method/property that is called in the DeviceMediator constructor.
It appears you're trying to listen for an event of some kind on the CallMonitor, so you could (and should if this is the case) add an event which the DeviceMediator subscribes to. In this case you can use RhinoMock to mock the event raising call like this:
[Test]
public void IncomingCallTest()
{
IEventRaiser callEvent;
CallMonitor monitor = mocks.Stub(args..);
using(mocks.Record())
{
callEvent = monitor.Stub(m => m.IncomingCall += null).IgnoreArguments().GetEventRaiser();
//rest of expectations...
}
using(mocks.Playback())
{
DeviceMediator mediator = new DeviceMediator(form, data, monitor);
callEvent.Raise(sender, args);
}
}
However, as noted above, you cannot mock constructor calls using RhinoMock since this would require some changes to the generated IL (assuming it's even possible).
I do not have too much experience with Rhino in particular, but did you try casting the callMonitor to a CallMonitor in the call to Return?
For example:
Expect.Call(new CallMonitor(null)).Return((CallMonitor)callMonitor);
EDIT:
On second thought, it looks like Return might be a generic method, which means this could be an additional option
Expect.Call(new CallMonitor(null)).Return<CallMonitor>(callMonitor);

Categories