Using the WPF Dispatcher in unit tests - c#

I'm having trouble getting the Dispatcher to run a delegate I'm passing to it when unit testing. Everything works fine when I'm running the program, but, during a unit test the following code will not run:
this.Dispatcher.BeginInvoke(new ThreadStart(delegate
{
this.Users.Clear();
foreach (User user in e.Results)
{
this.Users.Add(user);
}
}), DispatcherPriority.Normal, null);
I have this code in my viewmodel base class to get a Dispatcher:
if (Application.Current != null)
{
this.Dispatcher = Application.Current.Dispatcher;
}
else
{
this.Dispatcher = Dispatcher.CurrentDispatcher;
}
Is there something I need to do to initialise the Dispatcher for unit tests? The Dispatcher never runs the code in the delegate.

By using the Visual Studio Unit Test Framework you don’t need to initialize the Dispatcher yourself. You are absolutely right, that the Dispatcher doesn’t automatically process its queue.
You can write a simple helper method “DispatcherUtil.DoEvents()” which tells the Dispatcher to process its queue.
C# Code:
public static class DispatcherUtil
{
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
You find this class too in the WPF Application Framework (WAF).

We've solved this issue by simply mocking out the dispatcher behind an interface, and pulling in the interface from our IOC container. Here's the interface:
public interface IDispatcher
{
void Dispatch( Delegate method, params object[] args );
}
Here's the concrete implementation registered in the IOC container for the real app
[Export(typeof(IDispatcher))]
public class ApplicationDispatcher : IDispatcher
{
public void Dispatch( Delegate method, params object[] args )
{ UnderlyingDispatcher.BeginInvoke(method, args); }
// -----
Dispatcher UnderlyingDispatcher
{
get
{
if( App.Current == null )
throw new InvalidOperationException("You must call this method from within a running WPF application!");
if( App.Current.Dispatcher == null )
throw new InvalidOperationException("You must call this method from within a running WPF application with an active dispatcher!");
return App.Current.Dispatcher;
}
}
}
And here's a mock one that we supply to the code during unit tests:
public class MockDispatcher : IDispatcher
{
public void Dispatch(Delegate method, params object[] args)
{ method.DynamicInvoke(args); }
}
We also have a variant of the MockDispatcher which executes delegates in a background thread, but it's not neccessary most of the time

You can unit test using a dispatcher, you just need to use the DispatcherFrame. Here is an example of one of my unit tests that uses the DispatcherFrame to force the dispatcher queue to execute.
[TestMethod]
public void DomainCollection_AddDomainObjectFromWorkerThread()
{
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
DispatcherFrame frame = new DispatcherFrame();
IDomainCollectionMetaData domainCollectionMetaData = this.GenerateIDomainCollectionMetaData();
IDomainObject parentDomainObject = MockRepository.GenerateMock<IDomainObject>();
DomainCollection sut = new DomainCollection(dispatcher, domainCollectionMetaData, parentDomainObject);
IDomainObject domainObject = MockRepository.GenerateMock<IDomainObject>();
sut.SetAsLoaded();
bool raisedCollectionChanged = false;
sut.ObservableCollection.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e)
{
raisedCollectionChanged = true;
Assert.IsTrue(e.Action == NotifyCollectionChangedAction.Add, "The action was not add.");
Assert.IsTrue(e.NewStartingIndex == 0, "NewStartingIndex was not 0.");
Assert.IsTrue(e.NewItems[0] == domainObject, "NewItems not include added domain object.");
Assert.IsTrue(e.OldItems == null, "OldItems was not null.");
Assert.IsTrue(e.OldStartingIndex == -1, "OldStartingIndex was not -1.");
frame.Continue = false;
};
WorkerDelegate worker = new WorkerDelegate(delegate(DomainCollection domainCollection)
{
domainCollection.Add(domainObject);
});
IAsyncResult ar = worker.BeginInvoke(sut, null, null);
worker.EndInvoke(ar);
Dispatcher.PushFrame(frame);
Assert.IsTrue(raisedCollectionChanged, "CollectionChanged event not raised.");
}
I found out about it here.

I solved this problem by creating a new Application in my unit test setup.
Then any class under test which access to Application.Current.Dispatcher will find a dispatcher.
Because only one Application is allowed in an AppDomain I used the AssemblyInitialize and put it into its own class ApplicationInitializer.
[TestClass]
public class ApplicationInitializer
{
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext context)
{
var waitForApplicationRun = new TaskCompletionSource<bool>();
Task.Run(() =>
{
var application = new Application();
application.Startup += (s, e) => { waitForApplicationRun.SetResult(true); };
application.Run();
});
waitForApplicationRun.Task.Wait();
}
[AssemblyCleanup]
public static void AssemblyCleanup()
{
Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);
}
}
[TestClass]
public class MyTestClass
{
[TestMethod]
public void MyTestMethod()
{
// implementation can access Application.Current.Dispatcher
}
}

When you call Dispatcher.BeginInvoke, you are instructing the dispatcher to run the delegates on its thread when the thread is idle.
When running unit tests, the main thread will never be idle. It will run all of the tests then terminate.
To make this aspect unit testable you will have to change the underlying design so that it isn't using the main thread's dispatcher. Another alternative is to utilise the System.ComponentModel.BackgroundWorker to modify the users on a different thread. (This is just an example, it might be innappropriate depending upon the context).
Edit (5 months later)
I wrote this answer while unaware of the DispatcherFrame. I'm quite happy to have been wrong on this one - DispatcherFrame has turned out to be extremely useful.

Creating a DipatcherFrame worked great for me:
[TestMethod]
public void Search_for_item_returns_one_result()
{
var searchService = CreateSearchServiceWithExpectedResults("test", 1);
var eventAggregator = new SimpleEventAggregator();
var searchViewModel = new SearchViewModel(searchService, 10, eventAggregator) { SearchText = searchText };
var signal = new AutoResetEvent(false);
var frame = new DispatcherFrame();
// set the event to signal the frame
eventAggregator.Subscribe(new ProgressCompleteEvent(), () =>
{
signal.Set();
frame.Continue = false;
});
searchViewModel.Search(); // dispatcher call happening here
Dispatcher.PushFrame(frame);
signal.WaitOne();
Assert.AreEqual(1, searchViewModel.TotalFound);
}

If you want to apply the logic in jbe's answer to any dispatcher (not just Dispatcher.CurrentDispatcher, you can use the following extention method.
public static class DispatcherExtentions
{
public static void PumpUntilDry(this Dispatcher dispatcher)
{
DispatcherFrame frame = new DispatcherFrame();
dispatcher.BeginInvoke(
new Action(() => frame.Continue = false),
DispatcherPriority.Background);
Dispatcher.PushFrame(frame);
}
}
Usage:
Dispatcher d = getADispatcher();
d.PumpUntilDry();
To use with the current dispatcher:
Dispatcher.CurrentDispatcher.PumpUntilDry();
I prefer this variation because it can be used in more situations, is implemented using less code, and has a more intuitive syntax.
For additional background on DispatcherFrame, check out this excellent blog writeup.

If your goal is to avoid errors when accessing DependencyObjects, I suggest that, rather than playing with threads and Dispatcher explicitly, you simply make sure that your tests run in a (single) STAThread thread.
This may or may not suit your needs, for me at least it has always been enough for testing anything DependencyObject/WPF-related.
If you wish to try this, I can point you to several ways to do this :
If you use NUnit >= 2.5.0, there is a [RequiresSTA] attribute that can target test methods or classes. Beware though if you use an integrated test runner, as for example the R#4.5 NUnit runner seems to be based on an older version of NUnit and cannot use this attribute.
With older NUnit versions, you can set NUnit to use a [STAThread] thread with a config file, see for example this blog post by Chris Headgate.
Finally, the same blog post has a fallback method (which I've successfully used in the past) for creating your own [STAThread] thread to run your test on.

I'm using MSTest and Windows Forms technology with MVVM paradigm.
After trying many solutions finally this (found on Vincent Grondin blog) works for me:
internal Thread CreateDispatcher()
{
var dispatcherReadyEvent = new ManualResetEvent(false);
var dispatcherThread = new Thread(() =>
{
// This is here just to force the dispatcher
// infrastructure to be setup on this thread
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { }));
// Run the dispatcher so it starts processing the message
// loop dispatcher
dispatcherReadyEvent.Set();
Dispatcher.Run();
});
dispatcherThread.SetApartmentState(ApartmentState.STA);
dispatcherThread.IsBackground = true;
dispatcherThread.Start();
dispatcherReadyEvent.WaitOne();
SynchronizationContext
.SetSynchronizationContext(new DispatcherSynchronizationContext());
return dispatcherThread;
}
And use it like:
[TestMethod]
public void Foo()
{
Dispatcher
.FromThread(CreateDispatcher())
.Invoke(DispatcherPriority.Background, new DispatcherDelegate(() =>
{
_barViewModel.Command.Executed += (sender, args) => _done.Set();
_barViewModel.Command.DoExecute();
}));
Assert.IsTrue(_done.WaitOne(WAIT_TIME));
}

I accomplished this by wrapping Dispatcher in my own IDispatcher interface, and then using Moq to verify the call to it was made.
IDispatcher interface:
public interface IDispatcher
{
void BeginInvoke(Delegate action, params object[] args);
}
Real dispatcher implementation:
class RealDispatcher : IDispatcher
{
private readonly Dispatcher _dispatcher;
public RealDispatcher(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void BeginInvoke(Delegate method, params object[] args)
{
_dispatcher.BeginInvoke(method, args);
}
}
Initializing dispatcher in your class under test:
public ClassUnderTest(IDispatcher dispatcher = null)
{
_dispatcher = dispatcher ?? new UiDispatcher(Application.Current?.Dispatcher);
}
Mocking the dispatcher inside unit tests (in this case my event handler is OnMyEventHandler and accepts a single bool parameter called myBoolParameter)
[Test]
public void When_DoSomething_Then_InvokeMyEventHandler()
{
var dispatcher = new Mock<IDispatcher>();
ClassUnderTest classUnderTest = new ClassUnderTest(dispatcher.Object);
Action<bool> OnMyEventHanlder = delegate (bool myBoolParameter) { };
classUnderTest.OnMyEvent += OnMyEventHanlder;
classUnderTest.DoSomething();
//verify that OnMyEventHandler is invoked with 'false' argument passed in
dispatcher.Verify(p => p.BeginInvoke(OnMyEventHanlder, false), Times.Once);
}

How about running the test on a dedicated thread with Dispatcher support?
void RunTestWithDispatcher(Action testAction)
{
var thread = new Thread(() =>
{
var operation = Dispatcher.CurrentDispatcher.BeginInvoke(testAction);
operation.Completed += (s, e) =>
{
// Dispatcher finishes queued tasks before shuts down at idle priority (important for TransientEventTest)
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.ApplicationIdle);
};
Dispatcher.Run();
});
thread.IsBackground = true;
thread.TrySetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}

Winforms has a very easy and WPF compatible solution.
From your unit test project, reference System.Windows.Forms.
From your unit test when you want to wait for dispatcher events to finish processing, call
System.Windows.Forms.Application.DoEvents();
If you have a background thread that keeps adding Invokes to the dispatcher queue, then you'll need to have some sort of test and keep calling DoEvents until the background some other testable condition is met
while (vm.IsBusy)
{
System.Windows.Forms.Application.DoEvents();
}

I suggest adding one more method to the DispatcherUtil call it DoEventsSync() and just call the Dispatcher to Invoke instead of BeginInvoke. This is needed if you really have to wait until the Dispatcher processed all frames. I am posting this as another Answer not just a comment, since the whole class is to long:
public static class DispatcherUtil
{
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
public static void DoEventsSync()
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}

I'm late but this is how I do it:
public static void RunMessageLoop(Func<Task> action)
{
var originalContext = SynchronizationContext.Current;
Exception exception = null;
try
{
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
action.Invoke().ContinueWith(t =>
{
exception = t.Exception;
}, TaskContinuationOptions.OnlyOnFaulted).ContinueWith(t => Dispatcher.ExitAllFrames(),
TaskScheduler.FromCurrentSynchronizationContext());
Dispatcher.Run();
}
finally
{
SynchronizationContext.SetSynchronizationContext(originalContext);
}
if (exception != null) throw exception;
}

Simplest way I found is to just add a property like this to any ViewModel that needs to use the Dispatcher:
public static Dispatcher Dispatcher => Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher;
That way it works both in the application and when running unit tests.
I only had to use it in a few places in my entire application so I didn't mind repeating myself a bit.

It's a bit old post, BeginInvoke is not a preferable option today.
I was looking for a solution for mocking and had't found anything for InvokeAsync:
await App.Current.Dispatcher.InvokeAsync(() => something );
I've added new Class called Dispatcher, implementing IDispatcher, then inject into viewModel constructor:
public class Dispatcher : IDispatcher
{
public async Task DispatchAsync(Action action)
{
await App.Current.Dispatcher.InvokeAsync(action);
}
}
public interface IDispatcher
{
Task DispatchAsync(Action action);
}
Then in test I've injected MockDispatcher into viewModel in constructor:
internal class MockDispatcher : IDispatcher
{
public async Task DispatchAsync(Action action)
{
await Task.Run(action);
}
}
Use in the view model:
await m_dispatcher.DispatchAsync(() => something);

Related

C# Queuing async Task using BlockingCollection and process queue only after value returned for previous getter task in queue

Recently, i had a requirement to queue async tasks and i was introduced to BlockingCollection in this link
Queuing asynchronous task in C#
It worked and i'm having a slight change in requirement and need your guidance. I'm using the BlockingCollection as in #Stephen Cleary answer
This is the BlockingCollection from that link
public sealed class ExecutionQueue
{
//private readonly BlockingCollection<Func<Task>> _queue = new BlockingCollection<Func<Task>>();//commented this
private readonly BlockingCollection<Task> _queue = new BlockingCollection<Task>();
public ExecutionQueue() => Complete = Task.Run(() => ProcessQueueAsync());
public Task Completion { get; }
public void Complete() => _queue.CompleteAdding();
private async Task ProcessQueueAsync()
{
foreach (var value in _queue.GetConsumingEnumerable())
await value();
}
}
//public Task Run(Func<Task> lambda)
public Task Run(<Task> lambda)
{
var tcs = new TaskCompletionSource<object>();
_queue.Add(lamda);
return tcs.Task;
}
I need to queue certain DataBase tasks which is within a regular void method. I may not be able to change the signature of this method. How do i do them?
public static ExecutionQueue taskQueue = new ExecutionQueue();
private void SaveValesToDB(...)
{
var item = GetID(...);
...
taskQueue.Run(Task.Run(() =>
{
DBInstance.DBSaveValue1(...); // is it correct to wrap with Task.Run and add to queue? it should be queued and run asynchronously
});
...
}
We save and retrieve data from DB on and off. So, when we queue a DB call that is returning something like a getter, we want to ensure that until we receive the return value we don't process other items that are queued.
private void SaveValesToDB(...)
{
...
taskQueue.Run(Task.Run(() =>
{
DBInstance.DBSaveValue1(...); // is this correct? it should be queued and run asynchronously
});
...
taskQueue.Run(Task.Run(() =>
{
var result1 = DBInstance.DBGetValue2(...); // should be queued and run asynchronously;
LogData(result1);// not a DB call but believe it should be wrapped in here for the result1, correct?
});
/*so in above Task.Run, i want to ensure that until i receive result1
i don't process other items in the queue even
if they are added. how can i do that ?
The main thread should continue. */
...
var result 2 = DBInstance.DBGetValue3(...); // should be queued and run asynchronously
UpdateAdvancedLod(result1 +" "+result2);// here, should i block main thread until i get result1 ?
}
How to handle errors?
Please, guide me.
Edited:
if using Func<Task> in public Task Run(Func<Task> lambda) then is the below correct?
taskQueue.Run(async () =>
{
await Task.Run(() =>
{
DBInstance.DBSaveValue1(...);//is this correct
});
}
);
You could add this method to Stephen Cleary's ExecutionQueue class:
public Task Run(Action action)
{
return Run(() => Task.Run(action));
}
This is an overload of the existing public Task Run(Func<Task> lambda) method. This one delegates the execution of the supplied action to a ThreadPool thread.
Usage example:
var id = GetID();
var task = taskQueue.Run(() => DBInstance.DBSaveValue1(id));
await task; // Optional
Update: To propagate error notifications to the main thread, you could enhance the ExecutionQueue class with an Error event, which would be invoked in the captured context (captured at the time that the instance was created).
private readonly SynchronizationContext _capturedContext;
public event EventHandler<Exception> Error;
public ExecutionQueue() // Constructor
{
_capturedContext = SynchronizationContext.Current ?? new SynchronizationContext();
Completion = Task.Run(() => ProcessQueueAsync());
}
private void OnError(Exception ex)
{
var handler = Error; if (handler == null) return;
_capturedContext.Post(_ => handler.Invoke(this, ex), null);
}
The OnError should be called from inside the catch (Exception ex) block. This will work with Windows Forms apps and WPF apps, because their UI thread is equipped with a SynchronizationContext. It will not work with a Console app because there is no SynchronizationContext there (the Error event
will be raised in a random ThreadPool thread).

How can I resume task in the previous thread context after an "await"? [duplicate]

This question already has an answer here:
How do I create a custom SynchronizationContext so that all continuations can be processed by my own single-threaded event loop?
(1 answer)
Closed 3 years ago.
In Winforms/WPF the following code works:
var id = Thread.CurrentThread.ManagedThreadId;
await DoAsync();
var #equals = id == Thread.CurrentThread.ManagedThreadId; //TRUE
I know that await DoAsync().ConfigureAwait(false) will resume in another thread.
However, how can this WinForms/WPF behavior can be accomplished in the, say, Console App? In the console app, the above condition will return FALSE, regardless if I use ConfigureAwait(true/false). My app is not a console, it's just the same behavior.
I have several classes that implements IMyInterface with a method Task<IInterface> MyMethod() and in my starting point I need to start in a STA thread, so I create an STA thread like this
public static Task<TResult> Start<TResult>(Func<TResult> action, ApartmentState state, CancellationToken cancellation)
{
var completion = new TaskCompletionSource<TResult>();
var thread = new Thread(() =>
{
try
{
completion.SetResult(action());
}
catch (Exception ex)
{
completion.SetException(ex);
}
});
thread.IsBackground = true;
thread.SetApartmentState(state);
if (cancellation.IsCancellationRequested)
completion.SetCanceled();
else
thread.Start();
return completion.Task;
}
So I must ensure that in every class that implements IMyInterface it resumes to the STA thread created in the beginning.
How can one accomplish that?
As I mentioned in the comment above, this article is a great resource for answering this question. The author, Stephen Toub, is one of the leading experts on this stuff (indeed, he's a Software Engineer at Microsoft working on .NET), so you can trust whatever he says on the subject.
Here, I've adapted his example code to accomplish this. First, derive your own SynchronizationContext class:
private sealed class SingleThreadSynchronizationContext : SynchronizationContext
{
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> _queue =
new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
public override void Post(SendOrPostCallback d, object state)
=> _queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
public void RunOnCurrentThread()
{
KeyValuePair<SendOrPostCallback, object> workItem;
while (_queue.TryTake(out workItem, Timeout.Infinite))
workItem.Key(workItem.Value);
}
public void Complete() => _queue.CompleteAdding();
}
Then create a specialized message pump class:
public class AsyncPump
{
public static void Run(Func<Task> func)
{
var prevCtx = SynchronizationContext.Current;
try
{
var syncCtx = new SingleThreadSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(syncCtx);
var t = func();
t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default);
syncCtx.RunOnCurrentThread();
t.GetAwaiter().GetResult();
}
finally
{ SynchronizationContext.SetSynchronizationContext(prevCtx); }
}
}
Then you can use it like this:
[STAThread]
private static void Main(string[] args)
{
AsyncPump.Run(async () =>
{
await Task.Delay(2000);
});
// We're still on the Main thread!
}

Fluent-ASsertions ShouldRaisePropertyChangeFor does not work for async Tasks?

I have a simple class that implements INotifyPropertyChanged, I invoke the property change on another thread, and I had a pretty hard time getting FluentAsserts to see that the propertyChanged was invoked. It does not seem to happen if I use a Task.Delay in an async Task method. But it does if I just sleep the thread.
The SimpleNotify class:
namespace FluentAssertPropertyThreads
{
class SimpleNotify : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void onChange(string name)
{
this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name));
}
private int count = 0;
public int Count
{
get
{
return this.count;
}
set
{
if (this.count != value)
{
this.count = value;
this.onChange(nameof(this.Count));
}
}
}
}
}
and here are my unit tests:
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FluentAssertPropertyThreads
{
[TestClass]
public class UnitTest1
{
private SimpleNotify simpleNotify;
private int notifyCount;
private void bumpCount()
{
this.simpleNotify.Count++;
}
private void SimpleNotify_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
SimpleNotify simpleNotify = sender as SimpleNotify;
if (simpleNotify == null)
{
throw new ArgumentNullException(nameof(sender), "sender should be " + nameof(SimpleNotify));
}
if (e.PropertyName.Equals(nameof(SimpleNotify.Count), StringComparison.InvariantCultureIgnoreCase))
{
this.notifyCount++;
}
}
[TestInitialize]
public void TestSetup()
{
this.notifyCount = 0;
this.simpleNotify = new SimpleNotify();
this.simpleNotify.PropertyChanged += SimpleNotify_PropertyChanged;
this.simpleNotify.MonitorEvents();
Thread thread = new Thread(this.bumpCount)
{
IsBackground = true,
Name = #"My Background Thread",
Priority = ThreadPriority.Normal
};
thread.Start();
}
[TestMethod]
public async Task TestMethod1()
{
await Task.Delay(100);
this.notifyCount.Should().Be(1); //this passes, so I know that my notification has be executed.
this.simpleNotify.ShouldRaisePropertyChangeFor(x => x.Count); //but this fails, saying that I need to be monitoring the events (which I am above)
}
[TestMethod]
public void TestMethod2()
{
Thread.Sleep(100);
this.notifyCount.Should().Be(1); //this passes, so I know that my notification has be executed.
this.simpleNotify.ShouldRaisePropertyChangeFor(x => x.Count); //this passes as I expected
}
}
}
The exact error is:
System.InvalidOperationException: Object is not being monitored for events or has already been garbage collected. Use the MonitorEvents() extension method to start monitoring events.
I don't see how MonitorEvents would care if I use await or Thread.Sleep. What am I missing? I get that await leaves the method and comes back in, whereas Thread.Sleep does not.
So when it leaves the TestMethod1 during the await, it is hitting a dispose on an object that FluentAsserts is using to track the properties? Could it? Should it?
Yes, the things is like you said: await pauses the execution of current method and create a state machine to get back to the method after the Delay is done. But the caller (a UnitTest engine) doesn't expect your tests to be asynchronous and simply ends the execution, which leads to the disposal of the objects.
Stephen Cleary wrote a brilliant MSDN article about Unit testing and async/await keywords, you probably should move your code out to the method returning the Task and wait for all of it in test, something like this:
async Task Testing()
{
await Task.Delay(100);
this.notifyCount.Should().Be(1);
this.simpleNotify.ShouldRaisePropertyChangeFor(x => x.Count);
}
[TestMethod]
public async Task TestMethod1()
{
await Testing();
}
but this still may fail as the logic after await may execute after the disposable being disposed.
Looks like version 5.0.0 will include support for Async tests with monitoring.
This Issue was raised and the work completed just waiting on the documentation to be updated and version 5.0.0 to be released.
But for the time being there is a prerelease with the code changes 5.0.0-beta2 can get it from the prerelease versions on NuGet
From the change log:
{Breaking} Replaced the old thread-unsafe MonitorEvents API with a new
Monitor extension method that will return a thread-safe monitoring
scope that exposes methods like Should().Raise() and metadata such as
OccurredEvents and MonitoredEvents
So the code with the updated NuGet will look like this:
[TestInitialize]
public void TestSetup()
{
this.notifyCount = 0;
this.simpleNotify = new SimpleNotify();
this.simpleNotify.PropertyChanged += SimpleNotify_PropertyChanged;
Thread thread = new Thread(this.bumpCount)
{
IsBackground = true,
Name = #"My Background Thread",
Priority = ThreadPriority.Normal
};
thread.Start();
}
[TestMethod]
public async Task TestMethod1()
{
using (var MonitoredSimpleNotify = this.simpleNotify.Monitor())
{
await Task.Delay(100);
this.notifyCount.Should().Be(1);
MonitoredSimpleNotify.Should().RaisePropertyChangeFor(x => x.Count); // New API for Monitoring
}
}

How to unit test RelayCommand that Executes an async method?

As there is no RelayCommandAsync (at least not that I know of), how to test this scenario. For example:
public RelayCommand LoadJobCommand
{
get
{
return this.loadJobCommand ?? (
this.loadJobCommand =
new RelayCommand(
this.ExecuteLoadJobCommandAsync));
}
}
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
Test:
vm.LoadJobCommand.Execute()
Assert.IsTrue(vm.Jobs.Count > 0)
It really depends on what you are trying to test:
Test that the RelayCommand is properly hooked up and calls your async
method?
or
Test that the Async Method logic is correct?
1. Testing the RelayCommand trigger
1.a Using External Dependencies to verify
From my personal experience the easiest way to test that the trigger is wired up correctly to execute the command and then test that your class has interacted with another external class somewhere as expected. E.g.
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
private async void GetData(...)
{
var data = await _repo.GetData();
Jobs.Add(data);
}
Its fairly easy to test that your repo gets called.
public void TestUsingExternalDependency()
{
_repo.Setup(r => r.GetData())
.Returns(Task.Run(() => 5))
.Verifiable();
_vm.LoadJobCommand.Execute(null);
_repo.VerifyAll();
}
I sometimes even do this, so that it doesn't try to process everything:
[Test]
public void TestUsingExternalDependency()
{
_repo.Setup(r => r.GetData())
.Returns(() => { throw new Exception("TEST"); })
.Verifiable();
try
{
_vm.LoadJobCommand.Execute(null);
}
catch (Exception e)
{
e.Message.Should().Be("TEST");
}
_repo.VerifyAll();
}
1.b Using a Scheduler
Another option is to use a scheduler, and schedule tasks using that.
public interface IScheduler
{
void Execute(Action action);
}
// Injected when not under test
public class ThreadPoolScheduler : IScheduler
{
public void Execute(Action action)
{
Task.Run(action);
}
}
// Used for testing
public class ImmediateScheduler : IScheduler
{
public void Execute(Action action)
{
action();
}
}
Then in your ViewModel
public ViewModelUnderTest(IRepository repo, IScheduler scheduler)
{
_repo = repo;
_scheduler = scheduler;
LoadJobCommand = new RelayCommand(ExecuteLoadJobCommandAsync);
}
private void ExecuteLoadJobCommandAsync()
{
_scheduler.Execute(GetData);
}
private void GetData()
{
var a = _repo.GetData().Result;
Jobs.Add(a);
}
And your test
[Test]
public void TestUsingScheduler()
{
_repo.Setup(r => r.GetData()).Returns(Task.Run(() => 2));
_vm = new ViewModelUnderTest(_repo.Object, new ImmediateScheduler());
_vm.LoadJobCommand.Execute(null);
_vm.Jobs.Should().NotBeEmpty();
}
2. Testing the GetData Logic
If you are looking to test get GetData() logic or even the ExecuteLoadJobCommandAsync() logic. Then you should definitely make the method you want to test, as Internal, and mark your assmebly as InternalsVisibleTo so that you can call those methods directly from your test class.
Why don't you cover GetData(...) method with tests? I don't see any sense in testing relay commands
I was not using async/await but I have run in to a similar problem in the past. The situation I was in is the method called a Task.Run( inside of itself and the unit test was verifying that the ViewModel was calling the service with the correct number of times with the correct parameters.
The way we solved this was we had our Mock of the service that was being called use a ManualResetEventSlim, then the unit test waited for that reset event to be called before proceeding.
[TestMethod]
public void EXAMPLE()
{
using (var container = new UnityAutoMoqContainer())
{
//(SNIP)
var serviceMock = container.GetMock<ITreatmentPlanService>();
var resetEvent = new ManualResetEventSlim();
serviceMock.Setup(x=>x.GetSinglePatientViewTable(dateWindow, currentPatient, false))
.Returns(() =>
{
resetEvent.Set();
return new ObservableCollection<SinglePatientViewDataRow>();
});
var viewModel = container.Resolve<SinglePatientViewModel>();
//(SNIP)
viewModel.PatientsHadTPClosed(guids, Guid.NewGuid());
waited = resetEvent.Wait(timeout);
if(!waited)
Assert.Fail("GetSinglePatientViewTable was not called within the timeout of {0} ms", timeout);
//(SNIP)
serviceMock.Verify(x => x.GetSinglePatientViewTable(dateWindow, currentPatient, false), Times.Once);
}
}
If this approach works or not for you all depends on what your unit test is actually testing. Because you check Assert.IsTrue(vm.Jobs.Count > 0) it looks like you have extra logic that is being done after the await GetData(...); call, so this might not be applicable for your current problem. However, this may be helpful for other unit tests you need to write for your view model.

How would you marshall a call to a background thread and execute it within its context in C#?

Let's say I have a UI thread and a background thread that subscribe to a custom thread-safe ObservableCollection that I created so that whenever the collection changes it executes the callback within the appropriate context.
Now let's say I add something to the collection (from either thread, doesn't matter which one) and it now has to marshall the callback to both threads. To execute the callback within the UI's context I can simply do a Dispatcher.Invoke(...) and it executes the callback within the UI's context; great.
Now I want to execute the callback within the background thread's context (don't ask me why, it may well be that whatever it's accessing is affinitized to that specific thread or has thread-local storage it needs to access); how would I do that?
Background threads don't have a dispatcher/message pumping mechanism so I can't use a dispatcher or SynchronizationContext, so how would one interrupt a background thread and have it execute my callback within its context?
EDIT: I keep getting answers that are obviously wrong so I must not have explained myself correctly. Forget the UI thread and UI dispatchers guys, they were meant to marshall calls to the UI thread, that's it! Imagine two worker threads A and B. If A modifies my collection then A is in charge of marshalling the callback to itself and to B. Executing the callback within A's context is easy since A was the one triggering it : simply call the delegate in place. Now A needs to marshall the callback to B... now what? Dispatcher and SynContext are useless in this situation.
A good idea might also be extending your own TaskScheduler, you will have to implement three methods:
QueueTask, TryExecuteTaskInline and GetScheduledTasks
you can read about it here
That way, anytime you need to run something on your dedicated thread you could just do:
Task.Factory.StartNew(() => { SomeAction }, SomeCancellationToken, TaskCreationOptions
new MyTaskSchedular());
and have it execute on your thread.
We have a component that must always run on the same STA background thread. We've achieved this by writing our own SynchronizationContext. This article is very helpful.
To summarise, you don't want to interrupt your worker thread, you want it to sit idle waiting for the next task that it should execute. You add jobs to a queue and it processes those jobs in order. The SynchronizationContext is a convenient abstraction around that idea. The SynchronizationContext is the owner of the worker thread - and the outside world does not interact with the thread directly: callers who want to execute a task on the worker thread make the request to the context which adds the job to the job queue. The worker is either working or polling the queue until another job is added, at which point it begins working again.
Update
Here is an example:
using System.Collections.Concurrent;
using System.Threading;
class LoadBalancedContext : SynchronizationContext
{
readonly Thread thread1;
readonly Thread thread2;
readonly ConcurrentQueue<JobInfo> jobs = new ConcurrentQueue<JobInfo>();
public LoadBalancedContext()
{
this.thread1 = new Thread(this.Poll) { Name = "T1" };
this.thread2 = new Thread(this.Poll) { Name = "T2" };
this.thread1.Start();
this.thread2.Start();
}
public override void Post(SendOrPostCallback d, object state)
{
this.jobs.Enqueue(new JobInfo { Callback = d, State = state });
}
void Poll()
{
while (true)
{
JobInfo info;
if (this.jobs.TryDequeue(out info))
{
info.Callback(info.State);
}
Thread.Sleep(100);
}
}
class JobInfo
{
public SendOrPostCallback Callback { get; set; }
public object State { get; set; }
}
}
Usage:
var context = new LoadBalancedContext();
SendOrPostCallback callback = x =>
{
Trace.WriteLine(Thread.CurrentThread.Name);
Thread.Sleep(200);
};
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
context.Post(callback, null);
Thread.Sleep(1000);
The Send case is slightly more involved as you will need to listen for a reset event.. This is not production quality, but should give you an idea ow what you need to do.
Hope that helps.
Forget dispatcher.invoke, forget the ui thread. Imagine I have 2 worker
threads and I want to dispatch my event to both worker threads; what
can I use?
I'd use two task schedulers for this (as #YuvalItzchakov's answer suggests), one for each thread. I'd also use a custom synchronization context for the worker thread, as #TheMouthofaCow's answer suggests.
That is, for a UI thread, I'd just save and use TaskScheduler.FromCurrentSynchronizationContext(). For the worker thread, I would start a thread and install a custom synchronization context on it, then use FromCurrentSynchronizationContext too.
Something like this (untested):
// UI thread
var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
using (var worker = new ThreadWithPumpingSyncContext())
{
// call the worker thread
var result = await worker.Run(async () =>
{
// worker thread
await Task.Delay(1000);
// call the UI thread
await Task.Factory.StartNew(async () =>
{
// UI thread
await Task.Delay(2000);
MessageBox.Show("UI Thread!"),
// call the worker thread
await worker.Run(() =>
{
// worker thread
Thread.Sleep(3000)
});
// UI thread
await Task.Delay(4000);
}, uiTaskScheduler).Unwrap();
// worker thread
await Task.Delay(5000);
return Type.Missing; // or implement a non-generic version of Run
});
}
// ...
// ThreadWithSerialSyncContext renamed to ThreadWithPumpingSyncContext
class ThreadWithPumpingSyncContext : SynchronizationContext, IDisposable
{
public readonly TaskScheduler Scheduler; // can be used to run tasks on the pumping thread
readonly Task _mainThreadTask; // wrap the pumping thread as Task
readonly BlockingCollection<Action> _actions = new BlockingCollection<Action>();
// track async void methods
readonly object _lock = new Object();
volatile int _pendingOps = 0; // the number of pending async void method calls
volatile TaskCompletionSource<Empty> _pendingOpsTcs = null; // to wait for pending async void method calls
public ThreadWithPumpingSyncContext()
{
var tcs = new TaskCompletionSource<TaskScheduler>();
_mainThreadTask = Task.Factory.StartNew(() =>
{
try
{
SynchronizationContext.SetSynchronizationContext(this);
tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());
// pumping loop
foreach (var action in _actions.GetConsumingEnumerable())
action();
}
finally
{
SynchronizationContext.SetSynchronizationContext(null);
}
}, TaskCreationOptions.LongRunning);
Scheduler = tcs.Task.Result;
}
// SynchronizationContext methods
public override SynchronizationContext CreateCopy()
{
return this;
}
public override void OperationStarted()
{
lock (_lock)
{
if (_pendingOpsTcs != null && _pendingOpsTcs.Task.IsCompleted)
throw new InvalidOperationException("OperationStarted"); // shutdown requested
_pendingOps++;
}
}
public override void OperationCompleted()
{
lock (_lock)
{
_pendingOps--;
if (0 == _pendingOps && null != _pendingOpsTcs)
_pendingOpsTcs.SetResult(Empty.Value);
}
}
public override void Post(SendOrPostCallback d, object state)
{
_actions.Add(() => d(state));
}
public override void Send(SendOrPostCallback d, object state)
{
throw new NotImplementedException("Send");
}
// Task start helpers
public Task Run(Action action, CancellationToken token = default(CancellationToken))
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, this.Scheduler);
}
public Task Run(Func<Task> action, CancellationToken token = default(CancellationToken))
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, this.Scheduler).Unwrap();
}
public Task<T> Run<T>(Func<Task<T>> action, CancellationToken token = default(CancellationToken))
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, this.Scheduler).Unwrap();
}
// IDispose
public void Dispose()
{
var disposingAlready = false;
lock (_lock)
{
disposingAlready = null != _pendingOpsTcs;
if (!disposingAlready)
{
// do not allow new async void method calls
_pendingOpsTcs = new TaskCompletionSource<Empty>();
if (0 == _pendingOps)
_pendingOpsTcs.TrySetResult(Empty.Value);
}
}
// outside the lock
if (!disposingAlready)
{
// wait for pending async void method calls
_pendingOpsTcs.Task.Wait();
// request the end of the pumping loop
_actions.CompleteAdding();
}
_mainThreadTask.Wait();
}
struct Empty { public static readonly Empty Value = default(Empty); }
}
This give you some sort of cooperative asynchronous execution between two threads.

Categories