I'm trying to understand async actions and I'm a bit confused.
Actions are just glorified Delegates. Given the Actions
Action act = null;
act += () => { Console.WriteLine("Sync"); };
act += async () => { await File.AppendAllLinesAsync("C:/Test.Txt",
new[] { "Async File Operation" });
};
How can we invoke this async seeing as one of the delegates is async and the other is not. I've seen some extension methods in other SO answers simplified for the example would look like so:
public static void InvokeAsync(this Action action, AsyncCallback ar, object userObject = null)
{
var listeners = action.GetInvocationList();
foreach (var t in listeners)
{
var handler = (Action)t;
handler.BeginInvoke(ar, userObject);
}
}
I'm concerned if this even works because it looks like it invokes your callback for each listener which doesn't make sense.
I've only been using async with the more friendly version async/await so I do not understand this syntax as much. (I'm assuming the callback would be everything after the await and the userObject is equivalent to the dreadful SyncronizationContext that causes deadlocks if when calling sync without ConfigureAwait(false), but that is just a guess)
This is syntax inconvenient so I would perfer to use async await syntax, since async/await is called using duck-typing. I've read a blog about using async with delegates which for the example
public static class DelegateExtensions
{
public static TaskAwaiter GetAwaiter(this Action action)
{
Task task = new Task(action);
task.Start();
return task.GetAwaiter();
}
}
This too concerns me for a few reason, this looks much like an anti pattern.
Isn't this just creating a task which will run my action synchronous on a seperate thread? I also don't see this run through the invocation list.
Are either of these methods proper for invoking run delegates asynchronously?
Is there a way I can invoke an async delegate with the await syntax while still fully leveraging async?
What is the proper way to invoke async delegates with multiple functions in the invocation list?
I think Eric Lippert's comment have clarified the situation more than I could ever.
Overall, if you need to act on the return type of a method, you shouldn't use multicast delegates. If you still have to, at least use a Func<Task> signature, then you can iterate on each individual delegate using GetInvocationList, as explained here.
But would it be really impossible to work your way out of a multicast delegate with async void method?
It turns out that you can be notified of beginning and end of async void methods by using a custom synchronization context and overriding the OperationStarted and OperationCompleted methods. We can also override the Post method to set the synchronization context of child operations, to capture subsequent async void calls.
Piecing it together, you could come with something like:
class Program
{
static async Task Main(string[] args)
{
Action act = null;
act += () => { Console.WriteLine("Sync"); };
act += async () =>
{
Callback();
await Task.Delay(1000);
Console.WriteLine("Async");
};
await AwaitAction(act);
Console.WriteLine("Done");
Console.ReadLine();
}
static async void Callback()
{
await Task.Delay(2000);
Console.WriteLine("Async2");
}
static Task AwaitAction(Action action)
{
var delegates = action.GetInvocationList();
var oldSynchronizationContext = SynchronizationContext.Current;
var asyncVoidSynchronizationContext = new AsyncVoidSynchronizationContext();
try
{
SynchronizationContext.SetSynchronizationContext(asyncVoidSynchronizationContext);
var tasks = new Task[delegates.Length];
for (int i = 0; i < delegates.Length; i++)
{
((Action)delegates[i]).Invoke();
tasks[i] = asyncVoidSynchronizationContext.GetTaskForLastOperation();
}
return Task.WhenAll(tasks);
}
finally
{
SynchronizationContext.SetSynchronizationContext(oldSynchronizationContext);
}
}
}
public class AsyncVoidSynchronizationContext : SynchronizationContext
{
private TaskCompletionSource<object> _tcs;
private Task _latestTask;
private int _operationCount;
public Task GetTaskForLastOperation()
{
if (_latestTask != null)
{
var task = _latestTask;
_latestTask = null;
return task;
}
return Task.CompletedTask;
}
public override void Post(SendOrPostCallback d, object state)
{
Task.Run(() =>
{
SynchronizationContext.SetSynchronizationContext(this);
d(state);
});
}
public override void OperationStarted()
{
if (Interlocked.Increment(ref _operationCount) == 1)
{
// First operation
_tcs = new TaskCompletionSource<object>();
_latestTask = _tcs.Task;
}
base.OperationStarted();
}
public override void OperationCompleted()
{
if (Interlocked.Decrement(ref _operationCount) == 0)
{
// Last operation
_tcs.TrySetResult(null);
}
base.OperationCompleted();
}
}
The output would be:
Sync
Async
Async2
Done
Of course, this code is provided just for recreational purpose. There's plenty of limitations, such as the fact the fact that it wouldn't work as-is if you're already using a synchronization context (such as the WPF one). I'm also certain that it has a few subtle bugs and concurrency issues here and there.
I am test driving a class that gets injected with a bunch of work tasks, runs the asynchronously and restarts them when completed until told to halt all tasks.
Since I am doing test first I needed to write a test that forces me to write the restart logic, and I have kind of successfully done this, but I don't think I did it very well.
Test code: (FakeTask is basically a test spy that keeps track on whether it was called and how many times)
[Fact]
public async void Start_GivenTask_RerunsTaskUntilStopped()
{
var agent = CreateKlarnaAgent();
var fakeTask = DoNothingTask();
agent.Start(fakeTask);
Thread.Sleep(500);
await agent.Stop();
Assert.True(fakeTask.TimesRun > 1);
}
(Relevant) production code:
public void Start(params IWorkTask[] workTasks)
{
_logWriter.Debug("Starting...");
_tasks = workTasks
.Select(workTask => workTask.DoWork().ContinueWith(task => OnTaskComplete(task, workTask)))
.ToArray();
}
private void OnTaskComplete(Task completedTask, IWorkTask workTask)
{
if (completedTask.IsFaulted)
{
foreach (var exception in completedTask.Exception.InnerExceptions)
{
_logWriter.Error("Unhandled exception thrown!", exception);
}
}
else workTask.DoWork().ContinueWith(task => OnTaskComplete(task, workTask));
}
public Task Stop()
{
return Task.WhenAll(_tasks)
.ContinueWith(t => { _logWriter.Debug("Stopped"); });
}
The test is now really depending on a race condition and it doesn't feel like a unit test at all. How can I get rid of the Thread.Sleep(500) call? Or is this simply something I should test in an integration test?
On a side note, I recommend against writing "task runners" in general, and also recommend against ContinueWith in particular since it is such a dangerous API.
In my opinion, the "repeat forever until canceled" logic is far more clearly expressed using a loop for "repeat" and a cancellation token for "canceled":
static async Task WorkAsync(Func<Task> doWork, CancellationToken token)
{
while (true)
{
await doWork();
token.ThrowIfCancellationRequested();
}
}
However, that said, if you want to unit test your "task runner" as-is, you'll need to make your FakeTask more intelligent. For example, you could have it set a signal when it reaches a given count and have your unit test wait on that:
class FakeTask : IWorkTask
{
private readonly TaskCompletionSource<object> _done = new TaskCompletionSource<object>();
public Task Done { get { return _done.Task; } }
public Task DoWork()
{
++TimesRun;
if (TimesRun > 1)
_done.TrySetResult(null);
return Task.CompletedTask;
}
}
[Fact]
public async Task Start_GivenTask_RerunsTaskUntilStopped()
{
var agent = CreateKlarnaAgent();
var fakeTask = DoNothingTask();
agent.Start(fakeTask);
await fakeTask.Done;
await agent.Stop();
Assert.True(fakeTask.TimesRun > 1); // spurious test at this point
}
I have a situation where I must call an async method synchronously, and it is done so as follows:
obj.asyncMethod().Wait(myCancelToken)
If the cancellation token is switched the disposable's within the task will not get disposed despite being activated via a using statement.
The below program illustrates the problem:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeakTest {
class Program {
static void Main(string[] args) {
try {
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask().Wait(timeout.Token);
} catch (OperationCanceledException error) {
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadKey();
}
static async Task LongRunningTask() {
using (var resource = new DisposableResource()) {
await Task.Run( () => Thread.Sleep(1000));
}
}
public class DisposableResource : IDisposable {
public static int Instances = 0;
public DisposableResource() {
Instances++;
}
public void Dispose() {
Instances--;
}
}
}
}
It seems Wait method just kills the task thread on cancellation instead of triggering an exception within that thread and letting it terminate naturally. Question is why?
You've cancelled the task returned by Wait(timeout.Token) not the one returned from LongRunningTask, if you want to cancel that one pass the token to Task.Run and also use await Task.Delay instead of Thread.Sleep and pass the token there as well.
static void Main(string[] args)
{
try
{
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask(timeout.Token).Wait();
}
catch (AggregateException error)
{
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadLine();
}
static async Task LongRunningTask(CancellationToken token)
{
using (var resource = new DisposableResource())
{
await Task.Run(async () => await Task.Delay(1000, token), token);
}
}
public class DisposableResource : IDisposable
{
public static int Instances = 0;
public DisposableResource()
{
Instances++;
}
public void Dispose()
{
Instances--;
}
}
Note that the using statment will still dispose of the resource once the long running operation finishes. Run this example:
static void Main(string[] args)
{
try {
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask().Wait(timeout.Token);
} catch (OperationCanceledException error) {
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadKey();
}
static async Task LongRunningTask()
{
using (var resource = new DisposableResource())
{
await Task.Run(() => Thread.Sleep(1000));
}
}
public class DisposableResource : IDisposable
{
public static int Instances = 0;
public DisposableResource()
{
Instances++;
}
public void Dispose()
{
Instances--;
Console.WriteLine("Disposed resource. Leaked Instances = {0}", Instances);
}
}
Output
Leaked Instances = 1
Disposed resource. Leaked Instances = 0
It seems Wait method just kills the task thread on cancellation instead of triggering an exception within that thread
You are incorrect, on when you cancel the only thing that happens is you stop waiting for Wait(myCancelToken) to complete, the task is still running in the background.
In order to cancel the background task you must pass the cancelation token into all of the methods down the chain. If you want the innermost layer (the long running one) to stop early that code must call token.ThrowIfCancellationRequested() throughout its code.
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.
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);