I have a unit test project using xUnit.net v.2.3.1 for my ASP.NET Core 2.0 web app.
My test should focus on testing a given DataEntry instance: DataEntry instances are generated by the async method GenerateData() in my DataService class, which looks like:
public class DataService {
...
public async Task<List<DataEntry>> GenerateData() {
...
}
...
}
I am writing this test case as a Theory so my test can focus on a DataEntry instance at a time. Here is the code:
[Theory]
[MemberData(nameof(GetDataEntries))]
public void Test_DataEntry(DataEntry entry) {
// my assertions
Assert.NotNull(entry);
...
}
public static async Task<IEnumerable<object[]>> GetDataEntries() {
var service = new DataService();
List<DataEntry> entries = await service.GenerateData().ConfigureAwait(false);
return entries.Select(e => new object[] { e });
}
However, I get the following error at compile time:
MemberData must reference a data type assignable to 'System.Collections.Generic.IEnumerable<object[]>'. The referenced type 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object[]>>' is not valid.
From the error description, it seems xUnit.net does not allow MemberData to use an async static method, like my GetDataEntries() one. Is there any functionality gap in xUnit.net I should be aware of?
Now, I know I could switch my Theory into a Fact and loop through each DataEntry in the list returned by my DataService, however I would prefer to keep a Theory setup as my test would be cleaner and focused on DataEntry instead of List<DataEntry>.
Question: is there any way in xUnit.net to let my Theory get data from my DataService async API? Please, note the DataService class cannot be changed nor extended to provide data synchronously.
EDIT
I am looking for a way through async/await and would prefer to avoid any usage of blocking calls such as Task<T>.Result e.g. on my GenerateData() method, as the underlying thread will be blocked til the operation completes.
This is relevant in my test project as I have other similar test cases where data should be retrieved in the same way and therefore I want to avoid ending up with too many blocking calls, but instead keeping the async/await propagation.
Until xUnit allows async theory data, you can use Task<T> instances as theory data and await them inside the test method (note that test methods can be async):
public static IEnumerable<object> GetDataEntries() {
var service = new DataService();
yield return new object[] { service.GenerateData() };
}
[Theory]
[MemberData(nameof(GetDataEntries))]
public async Task Test_DataEntry(Task<List<DataEntry>> task) {
List<DataEntry> entries = await task;
for (int i = 0; i < entries.Count; i++) {
// my assertions
Assert.NotNull(entries[i]);
}
}
This functionality is not provided internally. You can try following:
Write your CustomMemberDataAttribute by inheriting DataAttribute.
Override 'GetData' method of parent class.
Make the method async, that, provides data.
Call async data provider method from 'GetData' method.
Use your CustomMemberDataAttribute to decorate test cases.
You can refer following link to write your custom attribute.
Keep other method same, just modify 'GetData' method as discuss above.
https://github.com/xunit/xunit/blob/bccfcccf26b2c63c90573fe1a17e6572882ef39c/src/xunit.core/MemberDataAttributeBase.cs
Related
I am running Unit Tests for my Xamarin.Forms application, and the Unit Tests throw Xamarin.Essentials.NotImplementedInReferenceAssemblyException:
I have created a Unit Test project for the app (using NUnit 3.12.0) and have written the below code to test the functionality.
[TestFixture()]
public class Test
{
[Test()]
public void TestCase()
{
AutoResetEvent autoEvent = new AutoResetEvent(true);
SomeClass someClass = new SomeClass();
someClass.SomeFunction((response) =>
{
Assert.AreEqual(response, "Hello")
autoEvent.Set();
});
autoEvent.WaitOne(); //** Xamarin.Essentials.NotImplementedInReferenceAssemblyException thrown here**
}
}
Below is the code under test from the Xamarin.Forms app:
public class SomeClass
{
public void SomeFunction(Action<string> callback)
{
// asynchronous code...
callback("Hello");
}
}
The above functionality works fine in the Xamarin.Forms app.
Note: I read that await/async can be used, however, I will have to make changes in the entire project. This is not a feasible solution for now.
Edit 1:
I have created a sample Xamarin.Forms project with Unit Tests in it. The project is available here
You need to add the Xamarin.Essentials NuGet Package to your Unit Test Project.
I highly recommend using Dependency Injection + Xamarin.Essentials.Interfaces, because certain Xamarin.Essentials APIs aren't implemented on .NET Core and you'll need to create your own implementation.
For example, here are some of the Xamarin.Essentials APIs I implemented in .NET Core for Unit Testing my GitTrends app:
AppInfo
Browser
DeviceInfo
Email
FileSystem
Launcher
MainThread
Preferences
SecureStorage
VersionTracking
While you have stated that the subject function cannot be made async at this time, the test however can be made async.
TaskCompletionSource can be used to wait for the callback to be invoked.
[TestFixture()]
public class Test {
[Test()]
public async Task TestCase() {
//Arrange
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
Action<string> callback = (arg) => {
tcs.TrySetResult(arg);
};
SomeClass someClass = new SomeClass();
//Act
someClass.SomeFunction(callback);
string response = await tcs.Task;
//Assert
Assert.AreEqual(response, "Hello")
}
}
The issue can be related to what exactly the call back is trying to do. For example the Connectivity function of Xamarin.Essentials won't work (and will throw that type of exception) if you are calling it from your unit test as it is not running on a mobile platform and thus doesn't have that feature implemented.
A solution to this, at least one I've done for that type of functionality, is to create an interface. So, to continue with the example above regarding the Connectivity feature we can do this:
Make an interface
public interface IConnectivityService {
bool CanConnect()
}
Define both an actual implementation of it that will be used during the app running, and one for testing purposes
public ConnectivityService : IConnectivityService {
//implement the method
}
public ConnectivtyServiceMock : IConnectivityService {
//implement the method, but this is a mock, so it can be very skinny
}
Update your View/VM to accept this interface, and inside of the test case instantiate the mock version of it and pass that in.
In such scenarios where we have to reference device specific implementations from a unit test, we have to abstract it away in an interface and use that implementation instead
I checked your code and it is not throwing any Xamarin.Essentials exception. To run the unit test, I had to add the "NUnit3TestAdapter" nuget package.
You will have to wait for callback otherwise test will crash. You can use TaskCompletionSource suggested by #Nkosi.
[Test()]
public async Task TestCase()
{
XamarinMock.Init();
WebApi webApi = new WebApi();
TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
Action<HttpResponseMessage> callback = (arg) => {
tcs.TrySetResult(arg);
};
webApi.Execute(callback);
var response = await tcs.Task;
Console.WriteLine(response);
Assert.AreEqual(response.StatusCode, HttpStatusCode.OK);
}
I have an API which is responsible for inserting text message details in database.
It does by making synchronous call to repository which I think could be implemented asynchronous way.How can I achieve this? Or what could be the best way to handle this scenario.Code snippet example is highly appreciated as I am still getting my ahead wrapping around .NET.
api:
public IHttpActionResult SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_service.SendSMS(smsNotification);
return Ok();
}
Service:
internal void SendSMS(SMSNotification smsNotification)
{
_repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
repo:
public virtual bool Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
sql.Execute();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
sql here is a custom thing and it has following methods:
public static int Execute(this IDataCommand #this);
[AsyncStateMachine(typeof(<ExecuteAsync>d__1))]
public static Task<int> ExecuteAsync(this IDataCommand #this);
Changing a blocking, typically IO-bound call (such as database, network or file system work) to async can make your app scale better.
This does have a flow-on affect through your API. That is, you need to be awaiting on asynchronous calls all the way up to the top-most call, otherwise, somewhere is going to block and you're just lost the benefit of calling an async API.
To demonstrate that, let's start from the bottom at the repository call, as that's the possibly expensive blocking operation can be made async. We alter sql.Execute to use the asynchronous version ExecutAsync version instead:
repo:
public virtual async Task<bool> Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
await sql.ExecuteAsync();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
Now here we have to change the signature of the method to return a Task wrapping a result of bool.
We also mark the method as async, so then we can use the "await" operator further down. Without doing this, we'd have to do more refactoring to manipulate and return the Task result ourselves, but the "async" modifier and "await" keyword let the compiler do that magic for us, and the rest of our code mostly looks like normal.
The mapper call doesn't really need to change:
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
The service call is now making a call to an async method, so because we want to await and not block on that async call, we have to also change this previously void method to an async method. Note we change it from "void" to "async Task"; you CAN mark a void method as "async void", but that's intended as a workaround for event handlers in Windows Forms and WPF apps; in every other case you want to change a "void" method to "async Task" when making it async.
Service:
internal async Task SendSMS(SMSNotification smsNotification)
{
await _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
Then finally, our API call can be made async, and await our service call:
api:
public async Task<IHttpActionResult> SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _service.SendSMS(smsNotification);
return Ok();
}
It's sometimes recommended that after you do a refactor like this, to rename the methods to end in "Async" by convention; however I don't think this is really compulsory, as so much of the .NET API surface is becoming async, it's almost redundant now.
It's worth getting your head around the async / await stuff though; I've tried to keep the example relatively brief. But I hope this at least gets you started.
Good day,
I am confused about unit testing the following:
1. MVC Controller:
[HttpGet]
public async Task<PartialViewResult> DoExternalCallsAsync()
{
var model = new MyModel();
await MyStaticLibrary.DoExternalWorkAsync(Server.MapPath("~\\") + "WorkSource.txt", model);
return PartialView("_MyResults", model);
}
2. Static library:
public static async Task DoExternalWorkAsync(string sourcePath, MyModel model)
{
var externalCalls =
System.IO.File.ReadAllLines(sourcePath)
.Where(line => (!string.IsNullOrEmpty(line) && line.First() != '#'))
.Select(p => DoExternalCall(p, model));
await Task.WhenAll(externalCalls);
}
private static async Task DoExternalCall(string urlPath, MyModel model)
{
var result = await GetExternalApiResultAysnc(urlPath);
// some code here...
return;
}
Basically, all that the controller does is call an external API, which does some work and returns a result or throws an error.
There are no interfaces or abstract classes with the external Api.
How do I go about unit testing this?
N. B. I am not at liberty to change the design of the external Api.
Thanks,
Using static classes or methods in your code makes that code hard to properly unit test. See Is static universally “evil” for unit testing and if so why does resharper recommend it?, Static class/method/property in unit test, stop it or not, When to use static classes in C#.
Wrap the static API call class into an instance class with an interface:
public interface IMyLibrary
{
Task DoExternalWorkAsync();
}
public class MyStaticLibrary : IMyLibrary
{
public async Task DoExternalWorkAsync(string sourcePath, MyModel model)
{
return await MyStaticLibrary.DoExternalWorkAsync(sourcePath, model);
}
}
Then you can inject an instance into the controller's constructor.
Because the only thing that should be unit tested in this controller action method:
Does the code call the library with the proper arguments?
Does the method return the proper object?
During testing, you can inject a mocked IMyLibrary in the controller and verify that the controller correctly calls the mock, and you can verify that the result is a PartialViewResult containing whatever it should contain.
The library is an implementation detail of performing some unit of work. It should be abstracted out completely. If you want to run integration tests, that's a different style of testing completely.
I have a web service, which I would like to do some unit testing on, however I am not sure how I can do this. Can anyone give any suggestions? Below is the webservice, it produces an object with three fields, but only when there is values in the database queue.
[WebMethod]
public CommandMessages GetDataLINQ()
{
CommandMessages result;
using (var dc = new TestProjectLinqSQLDataContext())
{
var command = dc.usp_dequeueTestProject();
result = command.Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return result;
}
}
You don't need to consume your data over the WebService to Unit test it. You can just create another project in your solution with a reference to your WebService project and call directly the methods.
First up, what you've posted can't really be Unit Tested at all; by definition, a Unit Test can have only a single reason to fail; However in your case, a single test of GetDataLINQ() (the "System Under Test" or "SUT") could fail because of a problem with any of the dependencies in the function - namely, TestProjectLinqSQLDataContext and usp_dequeueTestProject.
When you call this method from a Unit test, these dependencies at present are probably beyond your control because you didn't directly create them - they are most likely created in your page classes' constructor. (Note: this is an assumption on my part, and I could be wrong)
Also, because these dependencies are at present real "live" objects, which have hard dependencies on an actual database being present, it means your tests aren't able to run independently, which is another requirement for a Unit Test.
(I'll assume your page's class file is "MyPageClass" from now on, and I will pretend it's not a web page code-behind or asmx code-behind; because as other posters have pointed out, this only matters in the context of accessing the code via HTTP which we're not doing here)
var sut = new MyPageClass(); //sut now contains a DataContext over which the Test Method has no control.
var result = sut.GetDataLINQ(); //who know what might happen?
Consider some possible reasons for failure in this method when you call sut.GetDataLINQ():
new TestProjectLinqSQLDataContext() results in an exception because of a fault in TestProjectLinqSQLDataContext's constructor
dc.usp_dequeueTestProject() results in an exception because the database connection fails, or because the stored procedure has changed, or doesn't exist.
command.Select(...) results in an exception because of some as of yet unknown defect in the CommandMessage constructor
Probably many more reasons (i.e failure to perform correctly as opposed to an exception being thrown)
Because of the multiple ways to fail, you can't quickly and reliably tell what went wrong (certainly your test runner will indicate what type of exception threw, but that requires you to at least read the stack trace - you shouldn't need to do this for a Unit Test)
So, in order to do this you need to be able to setup your SUT - in this case, the GetDataLINQ function - such that any and all dependencies are fully under the control of the test method.
So if you really want to Unit Test this, you'll have to make some adjustments to your code. I'll outline the ideal scenario and then one alternative (of many) if you can't for whatever reason implement this. No error checking included in the code below, nor is it compiled so please forgive any typos, etc.
Ideal scenario
Abstract the dependencies, and inject them into the constructor.
Note that this ideal scenario will require you to introduce an IOC framework (Ninject, AutoFAC, Unity, Windsor, etc) into your project. It also requires a Mocking framework (Moq, etc).
1. Create an interface IDataRepository, which contains a method DequeueTestProject
public interface IDataRepository
{
public CommandMessages DequeueTestProject();
}
2. Declare IDataRepository as a dependency of MyPageClass
public class MyPageClass
{
readonly IDataRepository _repository;
public MyPageClass(IDataRepository repository)
{
_repository=repository;
}
}
3. Create an actual implementation of IDataRepository, which will be used in "real life" but not in your Unit Tests
public class RealDataRepository: IDataRepository
{
readonly MyProjectDataContext _dc;
public RealDataRepository()
{
_dc = new MyProjectDataContext(); //or however you do it.
}
public CommandMessages DequeueTestProject()
{
var command = dc.usp_dequeueTestProject();
result = command.Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return result;
}
}
This is where you will need to involve your IOC framework such that it can inject the correct IDataRepository (i.e RealDataRepository) whenever your MyPageClass is instantiated by the ASP.NET framework
4. Recode your GetDataLINQ() method to use the _repository member
public CommandMessages GetDataLINQ()
{
CommandMessages result;
return _repository.DequeueTestProject();
}
So what has this bought us? Well, consider now how you can test against the following specification for GetDataLINQ:
Must always invoke DequeueTestProject
Must return NULL if there is no data in the database
Must return a valid CommandMessages instance if there is data in the database.
Test 1 - Must always invoke DequeueTestProject
public void GetDataLINQ_AlwaysInvokesDequeueTestProject()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to just return null; we don't care about the return value for now
repo.Setup(r=>r.DequeueTestProject()).Returns(null);
//create the SUT, passing in the fake repository
var sut = new MyPageClass(repo.Object);
//call the method
sut.GetDataLINQ();
//Verify that repo.DequeueTestProject() was indeed called.
repo.Verify(r=>r.DequeueTestProject(),Times.Once);
}
Test 2 - Must return NULL if there is no data in the database
public void GetDataLINQ_ReturnsNULLIfDatabaseEmpty()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to return null;
repo.Setup(r=>r.DequeueTestProject()).Returns(null);
var sut = new MyPageClass(repo.Object);
//call the method but store the result this time:
var actual = sut.GetDataLINQ();
//Verify that the result is indeed NULL:
Assert.IsNull(actual);
}
Test 3 - Must return a valid CommandMessages instance if there is data in the database.
public void GetDataLINQ_ReturnsNCommandMessagesIfDatabaseNotEmpty()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to return null;
repo.Setup(r=>r.DequeueTestProject()).Returns(new CommandMessages("fake","fake","fake");
var sut = new MyPageClass(repo.Object);
//call the method but store the result this time:
var actual = sut.GetDataLINQ();
//Verify that the result is indeed NULL:
Assert.IsNotNull(actual);
}
Because we can Mock the IDataRepository interface, therfore we can completely control how it behaves.
We could even make it throw an exception, if we needed to test how GetDataLINQ responds to unforseen results.
This is the real benefit of abstracting your dependencies when it comes to Unit Testing (not to mention, it reduces coupling in your system because dependencies are not tied to a particular concrete type).
Not Quite ideal method
Introducing an IOC framework into your project may be a non-runner, so here is one alternative which is a compromise. There are other ways as well, this is just the first that sprang to mind.
Create the IDataRepository interface
Create the RealDataRepository class
Create other implementations of IDataRepository, which mimic the behaviour we created on the fly in the previous example. These are called stubs, and basically they are just classes with a single, predefined behaviour that never changes. This makes then ideal for testing, because you always know what will happen when you invoke them.
public class FakeEmptyDatabaseRepository:IDataRepository
{
public CommandMessages DequeueTestProject(){CallCount++;return null;}
//CallCount tracks if the method was invoked.
public int CallCount{get;private set;}
}
public class FakeFilledDatabaseRepository:IDataRepository
{
public CommandMessages DequeueTestProject(){CallCount++;return new CommandMessages("","","");}
public int CallCount{get;private set;}
}
Now modify the MyPageClass as per the first method, except do not declare IDataRepository on the constructor, instead do this:
public class MyPageClass
{
private IDataRepository _repository; //not read-only
public MyPageClass()
{
_repository = new RealDataRepository();
}
//here is the compromise; this method also returns the original repository so you can restore it if for some reason you need to during a test method.
public IDataRepository SetTestRepo(IDataRepository testRepo)
{
_repository = testRepo;
}
}
And finally, modify your unit tests to use FakeEmptyDatabaseRepository or FakeFilledDatabaseRepository as appropriate:
public void GetDataLINQ_AlwaysInvokesDequeueTestProject()
{
//create a fake implementation of IDataRepository
var repo = new FakeFilledDatabaseRepository();
var sut = new MyPageClass();
//stick in the stub:
sut.SetTestRepo(repo);
//call the method
sut.GetDataLINQ();
//Verify that repo.DequeueTestProject() was indeed called.
var expected=1;
Assert.AreEqual(expected,repo.CallCount);
}
Note that this second scenario is not an ivory-tower-ideal scenario and doesn't lead to strictly pure Unit tests (i.e if there were a defect in FakeEmptyDatabaseRepository your test could also fail) but it's a pretty good compromise; however if possible strive to achieve the first scenario as it leads to all kinds of other benefits and gets you one step closer to truly SOLID code.
Hope that helps.
I would change your Code as follows:
public class MyRepository
{
public CommandMessage DeQueueTestProject()
{
using (var dc = new TestProjectLinqSQLDataContext())
{
var results = dc.usp_dequeueTestProject().Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return results;
}
}
}
Then code your Web Method as:
[WebMethod]
public CommandMessages GetDataLINQ()
{
MyRepository db = new MyRepository();
return db.DeQueueTestProject();
}
Then Code your Unit Test:
[Test]
public void Test_MyRepository_DeQueueTestProject()
{
// Add your unit test using MyRepository
var r = new MyRepository();
var commandMessage = r.DeQueueTestProject();
Assert.AreEqual(commandMessage, new CommandMessage("What you want to compare"));
}
This allows your code to be reusable and is a common design pattern to have Data Repositories. You can now use your Repository Library everywhere you need it and test it in only one place and it should be good everywhere you use it. This way you don't have to worry about complicated tests calling WCF Services. This is a good way of testing Web Methods.
This is just a short explanation and can be improved much more, but this gets you in the right direction in building your Web Services.
I had trouble finding a simple, flexible pattern to allow me to write code in my ViewModels that in runtime would run asynchronously but during test-time run synchronously. This is what I came up with - does anyone have any suggestions? Is this a good path to go down? Are there better existing patterns out there?
LongRunningCall definition:
public class LongRunningCall
{
public Action ExecuteAction { get; set; }
public Action PostExecuteAction { get; set; }
public LongRunningCall(Action executeAction = null, Action postExecuteAction = null)
{
ExecuteAction = executeAction;
PostExecuteAction = postExecuteAction;
}
public void Execute(Action<Exception> onError)
{
try
{
ExecuteAction();
PostExecuteAction();
}
catch (Exception ex)
{
if (onError == null)
throw;
onError(ex);
}
}
public void ExecuteAsync(TaskScheduler scheduler, Action<Exception> onError)
{
var executeTask = Task.Factory.StartNew(ExecuteAction);
var postExecuteTask = executeTask.ContinueWith((t) =>
{
if (t.Exception != null)
throw t.Exception;
PostExecuteAction();
}, scheduler);
if (onError != null)
postExecuteTask.ContinueWith((t) => { onError(t.Exception); });
}
}
Usage:
var continueCall = new LongRunningCall(continueCommand_Execute, continueCommand_PostExecute);
if (svc.IsAsyncRequired)
continueCall.ExecuteAsync(TaskScheduler.FromCurrentSynchronizationContext(), continueCommand_Error);
else
continueCall.Execute(continueCommand_Error);
The only real pre-requisite is that you need to know at runtime if you're supposed to use async/sync. When I run my unit tests I send in a mock that tells my code to run synchronously, when the application actually runs IsAsyncRequired defaults to true;
Feedback?
I would prefer to encapsulate the decision on whether to execute code synchronously or asynchronously in a separate class that can be abstracted behind an interface such as this:
public interface ITaskExecuter
{
void ScheduleTask(
Action executeAction,
Action postExecuteAction,
Action<Exception> onException);
}
An instance of a class implementing ITaskExecuter can be injected where required.
You can inject different instances for testing versus production scenarios.
Usage becomes:
taskExecuter.ScheduleTask(
continueCommand_Execute,
continueCommand_PostExecute,
continueCommand_Error);
with no separate code paths in the calling class for test versus production.
You have the option of writing tests that:
just check the correct actions are passed to the task executer, or
configuring the task executer to execute the action synchronously and
test for the desired result, or
do both.
I did something very simmilar at my current job, but can't get to the code to copy/paste it right now...
Basically what I did was to create an IWorker interface, with a DoWork(Func<>) method.
Then I created 2 derived classes, one 'AsyncWorker' and one 'SyncWorker'. The SyncWorker just executes the passed in Func (synchronously), and the 'AsyncWorker' is a wrapper around a BackgroundWorker that sends the passed in Func off to the BackgroundWorker to be processed asynchronously.
Then, I changed my ViewModel to have an IWorker passed in. This moves the dependency resolution out of the ViewModel, so you can use a Dep. Inj. utility (I use Unity and Constructor injection).
Since I use Unity, in my unit test configuration, I then map IWorker to SyncWorker, and in production I map IWorker to AsyncWorker.
Hope that makes sense... I know it'd be easier if I had the code on hand...
Consider changing ExecuteAsync so that it will return a Task:
public Task ExecuteAsync(TaskScheduler scheduler, Action<Exception> onError)
So in production code, I would just call it as is:
longRunningCall.ExecuteAsync(
TaskScheduler.FromCurrentSynchronizationContext(),
continueCommand_Error);
But in unit tests, I would wait for the task to actually finish:
var task = longRunningCall.ExecuteAsync(
TaskScheduler.FromCurrentSynchronizationContext(),
continueCommand_Error);
task.Wait();