I am trying to unit test a simple method, and verify certain event has been published from that method, but finding hard time to set the mocks up.
//Class under test
public class TreatmentRoomModel : ITreatmentRoomModel
{
public TreatmentRoomModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
//Method under test
public void SetTreatmentInProgress(bool inProgress)
{
if (_isTreatmentInProgress == inProgress) return;
_isTreatmentInProgress = inProgress;
_eventAggregator.Publish(new TreatmentStatus(_isTreatmentInProgress), Execute.OnUIThread);
}
}
//TreatmentStatus event
public class TreatmentStatus
{
public TreatmentStatus(bool isInProgress)
{
IsInProgress = isInProgress;
}
public bool IsInProgress { get; private set; }
}
I am trying to test the method SetTreatmentInProgress and verify that a correct TreatmentStatus event is being published by the eventaggregator.
The event aggregator is typeof(Caliburn.Micro.IEventAggregator)
Below is the test setup
[TestClass]
public class TreatmentRoomModelTests
{
private Mock<IEventAggregator> _mockEventAggregator;
ITreatmentRoomModel _treatmentRoomModel;
private readonly TreatmentStatus _treatmentInProgressEvent = new TreatmentStatus(true);
private readonly TreatmentStatus _treatmentNotInProgressEvent = new TreatmentStatus(false);
[TestInitialize]
public void Initialize()
{
_mockEventAggregator = new Mock<IEventAggregator>();
//I am not sure how to set the property IsInProgress of TreatmentStatus to true? It is a privately set property through constructor.
_mockEventAggregator.Setup(x => x.Publish(It.IsAny<TreatmentStatus>(), Execute.OnUIThread));
//Or should I directly publish a true event, but then how to verify the event object without a reference to it.
//_mockEventAggregator.Setup(x => x.Publish(new TreatmentStatus(true), Execute.OnUIThread));
_treatmentRoomModel = new TreatmentRoomModel(_mockEventAggregator.Object);
}
[TestMethod]
public void SetTreatmentInProgressTest()
{
_treatmentRoomModel.SetTreatmentInProgress(true);
//This works, but I wan't to verify that the object of TreatmentStatus event has the property IsInProgress set to true.
_mockEventAggregator.Verify(x=>x.Publish(It.IsAny<TreatmentStatus>(), Execute.OnUIThread),Times.Once);
_treatmentRoomModel.SetTreatmentInProgress(false);
//Won't work, as it says this is getting called Times.None. I understand this may be because of different TreatmentStatus objects, which are raised and verified.
_mockEventAggregator.Verify(x=>x.Publish(new TreatmentStatus(false), Execute.OnUIThread),Times.Once);
}
}
Fix the expression to use It.Is<>
//This works, but I wan't to verify that the object of TreatmentStatus event has the property IsInProgress set to true.
_mockEventAggregator
.Verify(x=>x.Publish(It.Is<TreatmentStatus>(_ => _.IsInProgress == true), Execute.OnUIThread),Times.Once);
[TestMethod]
public void SetTreatmentInProgressTest()
{
var inProgress = true;
TreatmentStatus resultStatus = null;
_mockEventAggregator.Setup(x => x.Publish(It.IsAny<TreatmentStatus>(), Execute.OnUIThread))
.Callback<object,Action<Action>>((t,s) => resultStatus = (TreatmentStatus)t);
_treatmentRoomModel.SetTreatmentInProgress(inProgress);
Assert.IsNotNull(resultStatus);
Assert.IsTrue(resultStatus.IsInProgress);
Assert.IsTrue(_treatmentRoomModel.IsTreatmentInProgress);
}
Related
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.
I have an interface: IRemoteDataChangedListener
public interface IRemoteDataChangedListener<TData>
{
void DataReceived(TData newData);
}
And a class, RealtimeEventService
public class RealtimeEventService : IRealtimeEventService
{
private readonly IEventListener listener;
private readonly List<Tuple<Type, WeakReference>> dataCreated;
public RealtimeEventService(IEventListener eventListener)
{
this.dataCreated = new List<Tuple<Type, WeakReference>>();
this.listener = eventListener;
this.listener.EventReceived += this.ListenerOnEventReceived;
}
private void ListenerOnEventReceived(EventMessage message)
{
Type type = message.GetType();
if (type == typeof(NotificationReadEventMessage))
{
this.DataChanged((NotificationReadEventMessage)message);
}
}
public void SubscribeDataChanged<TEventMessage>(IRemoteDataChangedListener<TEventMessage> dataChangedListener) where TEventMessage : EventMessage, new()
{
this.dataCreated.Add(Tuple.Create(typeof(TEventMessage), new WeakReference(dataChangedListener)));
}
internal void DataChanged<TKey>(TKey newData)
where TKey : class, new()
{
LoopAndFilter<TKey>(this.dataCreated, listener => listener.DataReceived(newData));
}
private static void LoopAndFilter<TKey>(ICollection<Tuple<Type, WeakReference>> collection,
Action<IRemoteDataChangedListener<TKey>> success) where TKey : class
{
foreach (var reference in collection.ToArray())
{
if (!reference.Item2.IsAlive)
{
collection.Remove(reference);
continue;
}
if (reference.Item1 != typeof(TKey))
continue;
success((IRemoteDataChangedListener<TKey>)reference.Item2.Target);
}
}
#endregion
}
Whenever I create a test class that inherits IRemoteDataChangedListener with NotificationReadEventMessage as generic argument, and use an instance of this class with SubscribeDataChanged(), it gets hooked up just fine, and the method gets called.
Problem is, when I set the instance reference to null and run GC.Collect(), it should then be null, and the next time RealtimeEventService's LoopAndFilter method runs, it should detect that it is no longer alive, and remove the Weakreference from the list.
However it does not. When I inspect the value (In LoopAndFilter), after setting the instance reference to null in the test, the value still shows up as Alive being true.
And now I've been staring at this code for hours, and I simply cannot find anywhere I'd have a strong reference to the class...
Any help?
#Edit: Unit test (Using the Moq and Should libraries):
public class RealtimeEventServiceTests
{
[Fact]
public void VerifyWeakReferencesWorksAsIntended()
{
var eventListenerMock = new Mock<IEventListener>();
IRealtimeEventService service = new RealtimeEventService(eventListenerMock.Object);
bool called = false;
RemoteDataTest dataChangedListener = new RemoteDataTest();
dataChangedListener.Called += (sender, args) => called = true;
service.SubscribeDataChanged(dataChangedListener);
called.ShouldBeFalse();
((RealtimeEventService)service).DataChanged(new NotificationReadEventMessage());
called.ShouldBeTrue();
called = false;
dataChangedListener = null;
GC.Collect();
called.ShouldBeFalse();
((RealtimeEventService)service).DataChanged(new NotificationReadEventMessage());
called.ShouldBeFalse();
}
}
public class RemoteDataTest : IRemoteDataChangedListener<NotificationReadEventMessage>
{
public event EventHandler Called;
public void DataReceived(NotificationReadEventMessage newData)
{
if (Called != null) Called(this, null);
}
}
As it turns out, when I got home and compiled it at home, it ran just fine. And when I got back to work, it worked fine there as well.
Guess it's just one of those spooky bugs that magically vanish at inexplicable times. I'm just glad to be rid of it.
I did take the advice of Ewan & Scott Chamberlain, so thanks for that!
I'm trying to fix a garbage collection problem of a MVVM application which uses the following model of Undo stack.
The example is very minimalistic and real world code is much different, uses a factory class of undo lists per ViewModel instead of a single undolist but is representative:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Linq;
namespace ConsoleApplication9
{
public class UndoList
{
public bool IsUndoing { get; set; }
private Stack<Action> _undo = new Stack<Action>();
public Stack<Action> Undo
{
get { return _undo; }
set { _undo = value; }
}
private static UndoList _instance;
// singleton of the undo stack
public static UndoList Instance
{
get
{
if (_instance == null)
{
_instance = new UndoList();
}
return _instance;
}
}
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// execute the last undo operation
public void Undo()
{
UndoList.Instance.IsUndoing = true;
var action = UndoList.Instance.Undo.Pop();
action();
UndoList.Instance.IsUndoing = false;
}
// push an action into the undo stack
public void AddUndo(Action action)
{
if (UndoList.Instance.IsUndoing) return;
UndoList.Instance.Undo.Push(action);
}
// create push an action into the undo stack that resets a property value
public void AddUndo(string propertyName, object oldValue)
{
if (UndoList.Instance.IsUndoing) return;
var property = this.GetType().GetProperties().First(p => p.Name == propertyName);
Action action = () =>
{
property.SetValue(this, oldValue, null);
};
UndoList.Instance.Undo.Push(action);
}
}
public class TestModel : ViewModel
{
private bool _testProperty;
public bool TestProperty
{
get
{
return _testProperty;
}
set
{
base.AddUndo("TestProperty", _testProperty);
_testProperty = value;
}
}
// mock property indicating if a business action has been done for test
private bool _hasBusinessActionBeenDone;
public bool HasBusinessActionBeenDone
{
get
{
return _hasBusinessActionBeenDone;
}
set
{
_hasBusinessActionBeenDone = value;
}
}
public void DoBusinessAction()
{
AddUndo(() => { inverseBusinessAction(); });
businessAction();
}
private void businessAction()
{
// using fake property for brevity of example
this.HasBusinessActionBeenDone = true;
}
private void inverseBusinessAction()
{
// using fake property for brevity of example
this.HasBusinessActionBeenDone = false;
}
}
class Program
{
static void Test()
{
var vm = new TestModel();
// test undo of property
vm.TestProperty = true;
vm.Undo();
Debug.Assert(vm.TestProperty == false);
// test undo of business action
vm.DoBusinessAction();
vm.Undo();
Debug.Assert(vm.HasBusinessActionBeenDone == false);
// do it once more without Undo, so the undo stack has something
vm.DoBusinessAction();
}
static void Main(string[] args)
{
Program.Test();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
// at this point UndoList.Instance.Undo
// contains an Action which references the TestModel
// which will never be collected...
// in real world code knowing when to clear this is a problem
// because it is a singleton factory class for undolists per viewmodel type
// ideally would be to clear the list when there are no more references
// to the viewmodel type in question, but the Actions in the list prevent that
}
}
}
You see that when any viewModel goes out of scope the actions in the UndoList keep references to them. The real code groups various viewmodels into grouped undolists (viewModels that contain child viewmodels share the same undo stack), so it is difficult to know when and where to put the clearing.
I was wondering if there is some method to make those actions expire if they are the only one keeping references to the variables inside them?
Suggestions welcome!
I've got a solution for you. I don't like the use of the UndoList as a singleton, but I've kept it to provide you with a direct answer to your question. In practice I wouldn't use a singleton.
Now, you will find it very difficult to avoid capturing references to your view models in your actions. It would make your code very ugly if you tried. The best approach is to make your view models implement IDisposable and make sure that you dispose of them when they go out of scope. Remember that the garbage collector never calls Dispose so you must.
Using IDisposable is the standard model for cleaning up when an
instance is no longer needed.
So the first thing to define is a helper class that executes an action when it is disposed.
public sealed class AnonymousDisposable : IDisposable
{
private readonly Action _dispose;
private int _isDisposed;
public AnonymousDisposable(Action dispose)
{
_dispose = dispose;
}
public void Dispose()
{
if (Interlocked.Exchange(ref _isDisposed, 1) == 0)
{
_dispose();
}
}
}
Now I can write things like this to remove elements from lists:
var disposable = new AnonymousDisposable(() => list.Remove(item));
Later, when I call disposable.Dispose() the item is removed from the list.
Now here's your code re-implemented.
I've changed UndoList to be a static class, not a singleton. You can change it back if need be.
public static class UndoList
{
public static bool IsUndoing { get; private set; }
private static List<Action> _undos = new List<Action>();
public static IDisposable AddUndo(Action action)
{
var disposable = (IDisposable)null;
if (!IsUndoing)
{
disposable = new AnonymousDisposable(() => _undos.Remove(action));
_undos.Add(action);
}
return disposable ?? new AnonymousDisposable(() => { });
}
public static bool Undo()
{
IsUndoing = true;
var result = _undos.Count > 0;
if (result)
{
var action = _undos[_undos.Count - 1];
_undos.Remove(action);
action();
}
IsUndoing = false;
return result;
}
}
You'll notice that I've replaced the stack with a list. I did that because I need to remove items from inside the list.
Also, you can see that AddUndo now returns an IDisposable. Calling code needs to keep the return disposable and call Dispose when it wants to remove the action from the list.
I've also internalized the Undo action. It didn't make sense to have it in the view model. Calling Undo effectively pops the top item off of the list and executes the action and returns true. However, if the list is empty it returns false. You can use this for testing purposes.
The ViewModel class now looks like this:
public class ViewModel : IDisposable, INotifyPropertyChanged
{
public ViewModel()
{
_disposables = new List<IDisposable>();
_disposable = new AnonymousDisposable(() =>
_disposables.ForEach(d => d.Dispose()));
}
private readonly List<IDisposable> _disposables;
private readonly IDisposable _disposable;
public void Dispose()
{
_disposable.Dispose();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void AddUndo(Action action)
{ ... }
protected void SetUndoableValue<T>(Action<T> action, T newValue, T oldValue)
{ ... }
}
It implements IDisposable and internally, keeps track of a list of disposables and an anonymous disposable that will dispose of the items in the list when the view model itself is disposed of. Whew! A mouthful, but I hope that makes sense.
The AddUndo method body is this:
protected void AddUndo(Action action)
{
var disposable = (IDisposable)null;
Action inner = () =>
{
_disposables.Remove(disposable);
action();
};
disposable = UndoList.AddUndo(inner);
_disposables.Add(disposable);
}
Internally it calls UndoList.AddUndo passing in an action that will remove the returned IDisposable from the view model's list of undo actions when UndoList.Undo() is called - as well as, importantly, actually executing the action.
So this means that when the view model is disposed all of its outstanding undo actions are removed from the undo list and when Undo is called the associated disposable is removed from the view model. And this ensures that you are not keeping references to the view model when it is disposed of.
I created a helper function called SetUndoableValue that replaced your void AddUndo(string propertyName, object oldValue) method which wasn't strongly-typed and could cause you to have run-time errors.
protected void SetUndoableValue<T>(Action<T> action, T newValue, T oldValue)
{
this.AddUndo(() => action(oldValue));
action(newValue);
}
I made both of these methods protected as public seemed too promiscuous.
The TestModel is more-or-less the same:
public class TestModel : ViewModel
{
private bool _testProperty;
public bool TestProperty
{
get { return _testProperty; }
set
{
this.SetUndoableValue(v => _testProperty = v, value, _testProperty);
}
}
public bool HasBusinessActionBeenDone { get; set; }
public void DoBusinessAction()
{
this.AddUndo(this.inverseBusinessAction);
businessAction();
}
private void businessAction()
{
this.HasBusinessActionBeenDone = true;
}
private void inverseBusinessAction()
{
this.HasBusinessActionBeenDone = false;
}
}
And finally, here's the code that tests the UndoList functions correctly:
using (var vm = new TestModel())
{
Debug.Assert(UndoList.Undo() == false);
vm.TestProperty = true;
Debug.Assert(UndoList.Undo() == true);
Debug.Assert(UndoList.Undo() == false);
Debug.Assert(vm.TestProperty == false);
vm.DoBusinessAction();
Debug.Assert(UndoList.Undo() == true);
Debug.Assert(vm.HasBusinessActionBeenDone == false);
vm.DoBusinessAction();
}
Debug.Assert(UndoList.Undo() == false);
Please let me know if I can provide any more detail on anything.
If you can't clean it up any other way you could use WeakReference to hold property, but I think there would be other issues because this would still cause a Action instance to exist with a null reference attached to it.
As a quick look I would be more inclined to use the singleton to hold a registration to the model and let the model manage a instance list of all the undo actions attached to it. When the model goes out of scope call a clean-up method on it or implement a IDisposable type interface on it may if this fits. However depending on the implementation you may not need the singleton anyway.
I'm developing an asp.net (classic) application trying to implement the MVP pattern using this example. In trying to unit test my presenter and using the following pattern, the psuedocode for which looks like so
//base view interface
public interface IView
{
event EventHandler Init;
event EventHandler Load;
bool IsPostBack { get; }
void DataBind();
bool IsValid { get;}
}
//presenter psuedo code
public class SomePresenter
{
public SomePresenter(ISomeDomainService service, IView someView)
{
...
//HOW DO WE TEST/VERIFY THAT THIS REGISTRATION OCCURS?
someView.Init += OnInit;
someView.Load += OnLoad;
}
}
...
//consuming code that exercises the above code, that needs to be tested
var presenter = new SomePresenter(someDomainService, someView);
How do I verify that the presenter is doing what is expected i.e. registering for the Init and Load events? While this is easily done in the Phil Haack's example using Rhino mocks...
[Test]
public void VerifyAttachesToViewEvents()
{
viewMock.Load += null;
LastCall.IgnoreArguments();
viewMock.PostSaved += null;
LastCall.IgnoreArguments();
mocks.ReplayAll();
new PostEditController(viewMock,
this.dataServiceMock);
mocks.VerifyAll();
}
... how can we do this using MOQ?
The moq 4.13 introduced this feature. Now it is possible to verify if add\remove has been invoked. Therefore four new methods have been introduced:
SetupAdd
SetupRemove
VerifyAdd
VerifyRemove
Example
var mock = new Mock<IAdder<EventArgs>>();
mock.SetupAdd(m => m.Added += (sender, args) => { });
mock.Object.Added += (sender, args) => { };
mock.Object.Added += (sender, args) => { };
mock.VerifyAdd(m => m.Added += It.IsAny<EventHandler>(), Times.Exactly(2));
NB: Notice that in order to verify at least one setup should be added. The reason is to keep backward compatibility with the older version of moq.
It would appear that this functionality is not currently available in moq, but may appear in a future version (I had a look in the 4.0.812.4 beta, but it doesn't seem to be there).
It may be worth asking the question, "why does SomePresenter need to subscribe to the View's Load and Init events?" Presumably it is because the SomePresenter class needs to respond to those events. So it might be better to use the Raise method on your Mock<IView> to raise the Load and Init events, and then assert that SomePresenter did the right thing in response to them.
I know it's maybe too late for #Dilip, but this answer can be helpful for those who are trying to do the same.
Here is the test class
public delegate void SubscriptionHandler<T>(string name, T handler);
public class SomePresenterTest
{
[Test]
public void Subscription_Test()
{
var someServiceMock = new Mock<ISomeDomainService>();
var viewMock = new Mock<IView>();
//Setup your viewMock here
var someView = new FakeView(viewMock.Object);
EventHandler initHandler = null;
someView.Subscription += (n, h) => { if ((nameof(someView.Init)).Equals(n)) initHandler=h; };
Assert.IsNull(initHandler);
var presenter = new SomePresenter(someServiceMock.Object, someView);
Assert.IsNotNull(initHandler);
Assert.AreEqual("OnInit", initHandler.Method?.Name);
}
}
FakeView is a decorator implemented as follow (pay attention to Events:Init/Load{add;remove}):
public class FakeView : IView
{
public event SubscriptionHandler<EventHandler> Subscription;
public event SubscriptionHandler<EventHandler> Unsubscription;
private IView _view;
public FakeView(IView view)
{
Assert.IsNotNull(view);
_view = view;
}
public bool IsPostBack => _view.IsPostBack;
public bool IsValid => _view.IsValid;
public event EventHandler Init
{
add
{
Subscription?.Invoke(nameof(Init), value);
_view.Init += value;
}
remove
{
Unsubscription?.Invoke(nameof(Init), value);
_view.Init -= value;
}
}
public event EventHandler Load
{
add
{
Subscription?.Invoke(nameof(Load), value);
_view.Init += value;
}
remove
{
Unsubscription?.Invoke(nameof(Load), value);
_view.Init -= value;
}
}
public void DataBind()
{
_view.DataBind();
}
}
I spent some time with this question and the solution which I'm using in my project is:
Unit test:
// Arrange
TestedObject.Setup(x => x.OnEvent1());
TestedObject.Setup(x => x.OnEvent2());
// Act
TestedObject.Object.SubscribeEvents();
TestedObject.Raise(x => x.Event1 += null);
TestedObject.Raise(x => x.Event2 += null);
// Assert
TestedObject.Verify(x => x.OnEvent1(), Times.Once());
TestedObject.Verify(x => x.OnEvent2(), Times.Once());
Tested method:
this.Event1 += OnEvent1;
this.Event2 += OnEvent2;
So, first you have to mock the methods which you will assign the events, after you call the method which you want to test, and finally raise all subscribed events. If the event is really subscribed, you can check with Moq if the assigned method is called.
GLHF!
I'm setting up some RhinoMock tests but I can't work out why my expectations are failing.
Here are the class/ interface I'm testing:
public class LogOn {
public virtual ILogOn View { get; set; }
public virtual IDataProvider DataProvider { get; set; }
public void SetUp(ILogOn view) {
this.View = view;
this.DataProvider = ... //using dependancy injection to do the data provider, so I want it faked in tests
}
public void SetUpEvents() {
this.View.Submit += new EventHandler(View_Submit);
}
void View_Submit(object sender, EventArgs e) {
if ( this.DataProvider.LogOn(this.Username) ) {
this.View.SubmitSuccess();
} else {
this.View.SubmitFailure("Username is incorrect");
}
}
}
public interface ILogOn {
string Username { get; set; }
event EventHandler Submit;
void SubmitSuccess();
void SubmitFailure(string message);
}
And here is my test method:
[TestMethod]
public void LogOnFailure() {
var dataProvider = MockRepository.CreateStub<DataProvider>();
var presenter = MockRepository.CreateMock<LogOn>();
var view = MockRepository.CreateMock<ILogOn>();
dataProvider.Expect(d => d.LogOn(null)).Return(true).Repeat.Any();
presenter.Expect(p => p.DataProvider).Return(dataProvider).Repeat.Any();
presenter.Expect(p => p.View).Return(view).Repeat.Any();
presenter.Expect(p => p.SetUpEvents()).CallOriginalMethod();
view.Expect(v => v.Username).Return("invalid").Repeat.Any();
view.Expect(v => v.SubmitFail(null)).Constraints(Is.Same("Username is incorrect"));
presenter.SetUp(view);
presenter.SetUpEvents();
view.Raise(v => v.Submit += null, null, EventArgs.Empty);
presenter.VerifyAllExpectations();
view.VerifyAllExpectations();
}
The expectation that is failing is:
view.Expect(v => v.SubmitFail(null)).Constraints(Is.Same("Username is incorrect"));
(indicated by view.VerifyAllExpectations)
It says that that method is never executed, but when using the debugger I can step through and LogOn.View is accessed, does call the SubmitFailure method (with that argument) and return correctly.
I can't work out what is missing as watching the code does indicate that everything is executed at the right time and with the right values.
Edit: Ok, so I let out the code which is why I was mocking the LogOn class, it has a dependancy of an external data provider (which I'm stubbing as I don't care how it works). My appologies, I thought I was making this clearer but just made is worse!
The LogOn class is your system under test, so you should not be mocking that. You want to test that the LogOn class behaves as it should in the case of an invalid username. You are able to determine the correct behavior by passing in a mocked view that sets up the scenario you want. Try changing your test to what I have below.
[TestMethod]
public void LogonFailure()
{
var presenter = new LogOn();
var view = MockRepository.CreateMock<ILogOn>();
view.Expect(v => v.Username).Return("invalid").Repeat.Any();
view.Expect(v => v.SubmitFail(null)).Constraints(Is.Same("Username is incorrect"));
presenter.Setup(view);
view.Raise(v => v.Submit += null, null, EventArgs.Empty);
view.VerifyAllExpectations();
}