Test method with async await inside a task - c#

I have a this code
public class ClassToTest
{
private readonly IRepository repository;
public ClassToTest(DI GOES HERE){...}
public DoSomething()
{
Task.Run(async () => {
//some code
repository.ExecuteAsync();
}
}
}
public class Repository : IRepository
{
public Task ExecuteAsync()
{
using (var connection = new SqlConnection(DbConfiguration.DatabaseConnection))
{
return connection.ExecuteAsync(storedProcedure, parameters, commandType: CommandType.StoredProcedure, commandTimeout: Configuration.TransactionTimeout);
}
}
}
[Test]
public void TestMethod()
{
var repository = new Mock<IRepository>;
var classToTest = new ClassToTest();
classToTest.DoSomething();
repository.Veryfy(p => p.ExecuteAsync(), Times.Once());
}
The test fails with this message
Expected invocation on the mock once, but was 0 times: p => p.ExecuteAsync()
Does anyone knows why?
Thanks

As others have alluded, because you're calling Task.Run and not waiting for a response, the Unit test will likely complete before the background task is even started, hence the Moq Verify failure.
Also, your code won't compile as is - when asking a Q on StackOverflow, be sure to give a complete, compilable MVP.
Of special importance is the bug in the code you are trying to test. Repository.ExecuteAsync calls connection.ExecuteAsync, inside a using scope, but this isn't awaited. This will mean that the connection will be disposed before the task completes. You'll need to change the method to async and await the call to defer disposal of the connection.
The wrapper method DoSomething method shouldn't use Task.Run(), although, because it adds no value to the repository Task, it doesn't need to repeat the async / return await, either.
The caller (your Unit test, in this instance) can then await DoSomething (or if the caller genuinely wants to do further processing without awaiting the Task, then leave it to the caller to decide. At least this way, the caller gets a handle to the Task, to check on completion).
The final state of your code might look more like this:
public class ClassToTest
{
private readonly IRepository _repository;
public ClassToTest(IRepository repository)
{
_repository = repository;
}
// Doesn't necessarily need to be async
public Task DoSomething()
{
// We're return the wrapped task directly, and adding no additional value.
return repository.ExecuteAsync();
}
}
public class Repository : IRepository
{
public async Task ExecuteAsync()
{
using (var connection = new SqlConnection(DbConfiguration.DatabaseConnection))
{
// Here we do need to await, otherwise we'll dispose the connection
return await connection.ExecuteAsync(storedProcedure, parameters,
commandType: CommandType.StoredProcedure,
commandTimeout: Configuration.TransactionTimeout);
}
}
}
// NUnit has full support for async / await
[Test]
public async Task TestMethod()
{
var repository = new Mock<IRepository>();
var classToTest = new ClassToTest(repository.Object);
repository.Setup(_ => _.ExecuteAsync()).Returns(Task.FromResult((object)null));
// Moq also has support for async, e.g. .ReturnsAsync
// You need to await the test.
await classToTest.DoSomething();
repository.Verify(p => p.ExecuteAsync(), Times.Once());
}

Related

How to execute multiple parallel tasks on completion of a prior task

I have a situation where I need to call a web service and, on successful completion, do multiple things with the results returned from the web service. I have developed code that "works" -- just not as I intended. Specifically, I want to take the results from the call to the web service and pass those results onto multiple successive tasks that are to execute in parallel, but what I have at the moment executes the first successive task before starting the second.
I've put together a much simplified example of what I'm currently doing that'll hopefully help illustrate this situation. First, the implementation:
public interface IConfigurationSettings
{
int? ConfigurationSetting { get; set; }
}
public interface IPrintCommandHandler
{
System.Threading.Tasks.Task<bool> ExecuteAsync(byte[] reportContent);
}
public interface ISaveCommandHandler
{
System.Threading.Tasks.Task<bool> ExecuteAsync(byte[] reportContent);
}
public interface IWebService
{
System.Threading.Tasks.Task<object> RetrieveReportAsync(string searchToken, string reportFormat);
}
public class ReportCommandHandler
{
private readonly IConfigurationSettings _configurationSettings;
private readonly IPrintCommandHandler _printCommandHandler;
private readonly ISaveCommandHandler _saveCommandHandler;
private readonly IWebService _webService;
public ReportCommandHandler(IWebService webService, IPrintCommandHandler printCommandHandler, ISaveCommandHandler saveCommandHandler, IConfigurationSettings configurationSettings)
{
_webService = webService;
_printCommandHandler = printCommandHandler;
_saveCommandHandler = saveCommandHandler;
_configurationSettings = configurationSettings;
}
public async Task<bool> ExecuteAsync(string searchToken)
{
var reportTask = _webService.RetrieveReportAsync(searchToken, "PDF");
var nextStepTasks = new List<Task<bool>>();
// Run "print" task after report task.
var printTask = await reportTask.ContinueWith(task => _printCommandHandler.ExecuteAsync((byte[]) task.Result));
nextStepTasks.Add(printTask);
// Run "save" task after report task.
if (_configurationSettings.ConfigurationSetting.HasValue)
{
var saveTask = await reportTask.ContinueWith(task => _saveCommandHandler.ExecuteAsync((byte[]) task.Result));
nextStepTasks.Add(saveTask);
}
var reportTaskResult = await Task.WhenAll(nextStepTasks);
return reportTaskResult.Aggregate(true, (current, result) => current & result);
}
}
So, the web service (third party, nothing to do with me) has an endpoint for doing a search/lookup that, if successful, returns a reference number (I've called it a search token in my example). This reference number is then used to retrieve the results of the lookup (using a different endpoint) in any of several different formats.
The IWebService interface in this example is representative of an application service I created to manage interaction with the web service. The actual implementation has other methods on it for doing a lookup, ping, etc.
Just to make things more interesting, one of the successive tasks is required (will always execute after the primary task) but the other successive task is optional, execution subject to a configuration setting set elsewhere in the application.
To more easily demonstrate the issue, I created a unit test:
public class RhinoMockRepository : IDisposable
{
private readonly ArrayList _mockObjectRepository;
public RhinoMockRepository()
{
_mockObjectRepository = new ArrayList();
}
public T CreateMock<T>() where T : class
{
var mock = MockRepository.GenerateMock<T>();
_mockObjectRepository.Add(mock);
return mock;
}
public T CreateStub<T>() where T : class
{
return MockRepository.GenerateStub<T>();
}
public void Dispose()
{
foreach (var obj in _mockObjectRepository) obj.VerifyAllExpectations();
_mockObjectRepository.Clear();
}
}
[TestFixture]
public class TapTest
{
private const string SearchToken = "F71C8B50-ECD1-4C02-AD3F-6C24F1AF3D9A";
[Test]
public void ReportCommandExecutesPrintAndSave()
{
using (var repository = new RhinoMockRepository())
{
// Arrange
const string reportContent = "This is a PDF file.";
var reportContentBytes = System.Text.Encoding.Default.GetBytes(reportContent);
var retrieveReportResult = System.Threading.Tasks.Task.FromResult<object>(reportContentBytes);
var webServiceMock = repository.CreateMock<IWebService>();
webServiceMock.Stub(x => x.RetrieveReportAsync(SearchToken, "PDF")).Return(retrieveReportResult);
var printCommandHandlerMock = repository.CreateMock<IPrintCommandHandler>();
var printResult = System.Threading.Tasks.Task.FromResult(true);
printCommandHandlerMock
.Expect(x => x.ExecuteAsync(reportContentBytes))
//.WhenCalled(method => System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2)))
.Return(printResult);
var configurationSettingsStub = repository.CreateStub<IConfigurationSettings>();
configurationSettingsStub.ConfigurationSetting = 10;
var saveCommandHandlerMock = repository.CreateMock<ISaveCommandHandler>();
var saveResult = System.Threading.Tasks.Task.FromResult(true);
saveCommandHandlerMock.Expect(x => x.ExecuteAsync(reportContentBytes)).Return(saveResult);
// Act
var reportCommandHandler = new ReportCommandHandler(webServiceMock, printCommandHandlerMock, saveCommandHandlerMock, configurationSettingsStub);
var result = System.Threading.Tasks.Task
.Run(async () => await reportCommandHandler.ExecuteAsync(SearchToken))
.Result;
// Assert
Assert.That(result, Is.True);
}
}
}
Ideally, on completion of the call to RetrieveReportAsync() on IWebService both the "print" and "save" command handlers should be executed simultaneously, having received a copy of the results from RetrieveReportAsync(). However, if the call to WhenCalled... in the unit test is uncommented, and on stepping through the implementation of ReportCommandHandler.ExecuteAsync(), you can see that the "print" command executes and completes before it gets to the "save" command. Now, I am aware that the whole point of await is to suspend execution of the calling async method until the awaited code completes, but it isn't clear to me how to instantiate both the "print" and "save" commands (tasks) as continuations of the "report" task such that they both execute in parallel when the "report" task completes, and the "report" command is then able to return a result that is based on the results from both the "print" and "save" commands (tasks).
Your question really involves addressing two different goals:
How to wait for a task?
How to execute two other tasks concurrently?
I find the mixing of await and ContinueWith() in your code confusing. It's not clear to me why you did that. One of the key things await does for you is to automatically set up a continuation, so you don't have to call ContinueWith() explicitly. Yet, you do anyway.
On the assumption that's simply a mistake, out of lack of full understanding of how to accomplish your goal, here's how I'd have written your method:
public async Task<bool> ExecuteAsync(string searchToken)
{
var reportTaskResult = await _webService.RetrieveReportAsync(searchToken, "PDF");
var nextStepTasks = new List<Task<bool>>();
// Run "print" task after report task.
var printTask = _printCommandHandler.ExecuteAsync((byte[]) reportTaskResult);
nextStepTasks.Add(printTask);
// Run "save" task after report task.
if (_configurationSettings.ConfigurationSetting.HasValue)
{
var saveTask = _saveCommandHandler.ExecuteAsync((byte[]) reportTaskResult);
nextStepTasks.Add(saveTask);
}
var reportTaskResult = await Task.WhenAll(nextStepTasks);
return reportTaskResult.Aggregate(false, (current, result) => current | result);
}
In other words, do await the original task first. Then you know it's done and have its result. At that time, go ahead and start the other tasks, adding their Task object to your list, but not awaiting each one individually. Finally, await the entire list of tasks.

Calling EF6 FindAsync hangs the application

I'm trying to use Entity Framework 6's Async calls, but whenever I call the FindAsync, the application hangs, and I never get the control back. Below is the method using the Find, where everything goes fine.
public CaUsuario GetUsers(RFContext db, int id)
{
CaUsuario caUsuario = db.CaUsuarios.Find(id);
if (caUsuario == null)
throw new ObjectNotFoundException("User not found");
return caUsuario;
}
Below is my attempt to use the async, with Task return a the ASync call. When the FindAsync is called, I never receive the control back, and the application hangs.
public async Task<CaUsuario> GetUsers(RFContext db, int id)
{
CaUsuario caUsuario = await db.CaUsuarios.FindAsync(id);
if (caUsuario == null)
throw new ObjectNotFoundException("User not found");
return caUsuario;
}
What am I doing wrong?
It might hang in the event of not going "async all the way". Ensure that whatever is calling into the GetUsers is doing so with the async and await keywords, and not incorrectly attempting to use the .Result or .Wait().
Assume the following is a consuming class:
public class Consumer
{
private readonly IUserService _userService;
public Consumer(IUserService userService)
{
_userService = userService;
}
public async Task ConsumeAsync()
{
// Correct
var user = await _userService.GetUsers(1);
}
public void Consume()
{
// Will hang
var user = _userService.GetUsers(1).Result;
}
}
You are probably not doing async all the way through your call chain/stack. Using a combination of Task<T>.Result and await in the call chain will cause a deadlock.

Patterns for testing ICommand that call async methods

I am just looking at best practices for unit testing (NUnit) ICommand and specifically the MvxCommand implementation within MVVMCross
View Model
public ICommand GetAuthorisationCommand
{
get { return new MvxCommand(
async () => await GetAuthorisationToken(),
() => !string.IsNullOrWhiteSpace(UserName) && !string.IsNullOrWhiteSpace(Password)); }
}
private async Task GetAuthorisationToken()
{
// ...Do something async
}
Unit Test
[Test]
public async Task DoLogonCommandTest()
{
//Arrange
ViewModel vm = new ViewModel(clubCache, authorisationCache, authorisationService);
//Act
await Task.Run(() => vm.GetAuthorisationToken.Execute(null));
//Assert
Assert.Greater(MockDispatcher.Requests.Count, 0);
}
Now the problem I have is that the tests drop through with out awaiting the async operations and this feels a little hacky in calling the async method from the ICommand.
Are there any best practices in unit testing these kind of ICommands and async methods?
You can use MvxAsyncCommand (see: implementation) instead of MvxCommand and change the published type of GetAuthorisationCommand from ICommand to IMvxAsyncCommand (but that interface is not available via nuget, yet) and then you can call
await vm.GetAuthorisationToken.ExecuteAsync();
I think the answer with MvxAsyncCommand is the best long-term solution.
However, if you want something that works today without depending on prerelease software, you can follow this pattern which I have found helpful when dealing with asynchronous MVVM commands.
First, define an IAsyncCommand:
interface IAsyncCommand: ICommand
{
Task ExecuteAsync(object parameter);
}
Then you can define an AsyncCommand implementation as such:
public class AsyncCommand: MvxCommand, IAsyncCommand
{
private readonly Func<Task> _execute;
public AsyncCommand(Func<Task> execute)
: this(execute, null)
{
}
public AsyncCommand(Func<Task> execute, Func<bool> canExecute)
: base(async () => await execute(), canExecute)
{
_execute = execute;
}
public Task ExecuteAsync()
{
_execute();
}
}
And then use await command.ExecuteAsync() instead of command.Execute() in your unit tests.
As a command is a fire and forget event you dont get back a completion directly.
I would suggest splitting the test into two actions (or even creating two Unit test).
Test if the Command can be executed
Test if the Async Task return expected result
Something along the lines of:
//Act
var canExecute = vm.GetAuthorisationToken.CanExecute();
var result = await vm.GetAuthorisationToken();
However, is would require GetAuthorisationToken to change its protection level from private inorder to expose it for the unit test.
Alternatively
You can make use of a library such as AsyncEx, which can allow you to await the completion of the async call.
[Test]
public async Task DoLogonCommandTest()
{
AsyncContext.Run(() =>
{
//Arrange
ViewModel vm = new ViewModel(clubCache, authorisationCache, authorisationService);
//Act
await Task.Run(() => vm.GetAuthorisationToken.Execute(null));
});
//Assert
Assert.Greater(MockDispatcher.Requests.Count, 0);
}

How to use Microsoft Fakes to Shim Async Task method?

I'm using Microsoft Fakes to Shim an async method that invokes another method to get an implemented DbContext. Because database connection string is not supplied in the Unit Test while the method being invoked inside the async method needs it. Shim will not only skip the method that uses the connection string, but returns a customizable DbContext.
Here is the aysnc method implementation:
public async Task<AccountDataDataContext> GetAccountDataInstance(int accountId)
{
var account = await this.Accounts.FindAsync(accountId);
return AccountDataDataContext.GetInstance(account.AccountDataConnectionString);
}
However, I'm not familiar with Shim async method. What I did look like this:
ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 = (x, y, z) => new Task<AccountDataEntities.AccountDataDataContext>(() =>
{
return new SampleContext();// This is the fake context I created for replacing the AccountDataDataContext.
});
And SampleContext is implementing AccountDataDataContext as follows:
public class SampleContext: AccountDataDataContext
{
public SampleContext()
{
this.Samples = new TestDbSet<Sample>();
var data = new AccountDataRepository();
foreach (var item in data.GetFakeSamples())
{
this.Samples.Add(item);
}
}
}
Below is the code snippet for the test case:
[TestMethod]
public async Task SampleTest()
{
using (ShimsContext.Create())
{
//Arrange
SamplesController controller = ArrangeHelper(1);// This invokes the Shim code pasted in the second block and returns SamplesController object in this test class
var accountId = 1;
var serviceId = 2;
//Act
var response = await controller.GetSamples(accountId, serviceId);// The async method is invoked in the GetSamples(int32, int32) method.
var result = response.ToList();
//Assert
Assert.AreEqual(1, result.Count);
Assert.AreEqual("body 2", result[0].Body);
}
}
As the result, my test case is running forever. I think I might write the Shim lamdas expression completely wrong.
Any suggestion? Thank you.
You don't want to return a new Task. In fact, you should never, ever use the Task constructor. As I describe on my blog, it has no valid use cases at all.
Instead, use Task.FromResult:
ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 =
(x, y, z) => Task.FromResult(new SampleContext());
Task also has several other From* methods that are useful for unit testing (e.g., Task.FromException).

How to call some async code in an ASP.NET application_start

In our application_startup, we seed up our database with some fake data, if no data exists.
To do this, we're using the Async methods to store the data. Great. Only problem is, we're not sure how to do this in the application_startup because that's not an async method.
I've spent soooo much time trying to understand #StevenCleary's tutorials and I'm always getting deadlocks. I totally grok what he consistently says:
As a general rule, you should use "async all the way down"; that is, don't block on async code
but I just don't get how I can do that, in this case :(
Lets imagine this is the code I'm trying to play with...
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
await documentStore.InitializeAsync(someFakeData);
...
// Registers this database as a singleton.
Container.Register(documentStore);
}
and later on .. some code that uses this documentStore. It is injected via construction injection ...
public SomeController(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public ViewModel GetFoos()
{
using (var session = _documentStore.OpenSession())
{
... db code goes in here ...
}
}
Clarification
I'm not trying to do some async code in here. I'm actually trying to call this async method, synchronously. Sure, i loose the benefits of async blah blah de blah.. but i'm happy with that. This is start up and I'm happy to block on startup.
In this case, you're asynchronously initializing a shared resource. So, I recommend that you either save the Task itself, or introduce an asynchronous wrapper type.
Using Task:
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
var documentStoreTask = documentStore.InitializeAsync(someFakeData);
...
// Registers this database task as a singleton.
Container.Register(documentStoreTask);
}
That may be too awkward, though, depending on Container. In that case, you can introduce an asynchronous wrapper type:
public sealed class DocumentStoreWrapper
{
private readonly Task<DocumentStore> _documentStore;
public DocumentStoreWrapper(Data data)
{
_documentStore = CreateDocumentStoreAsync(data);
}
private static async Task<DocumentStore> CreateDocumentStoreAsync(Data data)
{
var result = new DocumentStore();
await documentStore.InitializeAsync(data);
...
return result;
}
public Task<DocumentStore> DocumentStoreTask { get { return _documentStore; } }
}
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStoreWrapper = new DocumentStoreWrapper(someFakeData);
...
// Registers this database wrapper as a singleton.
Container.Register(documentStoreWrapper);
}
Or, you could use AsyncLazy<T>, which does much the same thing but uses a background thread to execute the initialization code.
You can use of Task.Run(() => YourAsyncMethod()); inside of none async method like:
protected void Application_Start()
{
Task.Run(() => MyAsyncMethod(true));
}
This is an old topic, but it's popped up in my search and maybe it will for others.
For what the OP has requested (ie. To run an async method in a synchronous way from inside a synchronous method, and block until it's finished), is there some reason that the use of Task.WaitAll would not be a simple and adequate way of addressing this?
protected void Application_Start()
{
Task.WaitAll(MyAsyncMethod(true));
}
public static class AsyncHelper
{
private static readonly TaskFactory MyTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
then use as
AsyncHelper.RunSync(ProcessAsync);
private async Task ProcessAsync(){ ....

Categories