Get async callback value in unittest debug - c#

I got UnitTest method which calls method with callback
[Test]
public void GetUserAsyncTest()
{
User result;
_restTest.GetUserAsync((user) =>
{
result = user;
});
Assert.AreEqual("xy", result.Email);
}
This is my method signature
/// <summary>
/// Retrieve the User details for the currently authenticated User
/// </summary>
/// <param name="callback">Method to call upon successful completion</param>
public void GetUserAsync(Action<User> callback)
How can I test this and get value from callback? Currently my result is always null which is logical.

Use an event to wait until the async method has finished:
[Test]
public void GetUserAsyncTest()
{
//Action<User> user = null;
User result;
ManualResetEvent waitEvent = new ManualResetEvent(false);
_restTest.GetUserAsync((user) =>
{
result = user;
waitEvent.Set();
});
waitEvent.WaitOne();
Assert.AreEqual("xy", result.Email);
}
Also changed user.Email to result.Email. Suspected you want to check the result variable.

Related

Update React front-end from .Net back-end

I am recently approaching React and I was wondering how can I send from my ASP.NET back-end some updates to all the front-ends, but first let me explain myself.
I am sending some inputs from one front-end to the back-end. Just for reference here's how I do it:
Front-end
async SendInput(data) {
await fetch('Status/ChangeState', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
Back-end
[ApiController]
[Route("[controller]")]
public class StatusController : Controller
{
[HttpPost("ChangeState")]
public void ChangeState([FromBody] short i)
{
//Do stuff here
}
}
Now what I need is keep all the connected users variables updated when this "state" is changed by one of them.
My first thought was to send repeatedly a POST or GET request to the back-end with setInterval(), but even if there are not so many users I still would prefer a method like Long polling or Server Sent Events.
What would a good recommended approach be? If possible include an example.
The simplest possible state manager in my opinion for long polling can be created with a TaskCompletionSource. The controller waits for a state change with await and sends the result as ActionResult. The client opens the connection to this controller immediately after receiving the data.
However, I would only use this implementation for very small projects and is intended more as an illustrative example. For larger projects SignalR can be used.
/// <summary>
/// Class for your state properties.
/// </summary>
public class State
{
public string MyStateField1 { get; set; } = string.Empty;
public string MyStateField2 { get; set; } = string.Empty;
}
/// <summary>
/// StateManager
/// Register with
/// services.AddSingleton<StateManager<State>>();
/// in ConfigureServices().
/// </summary>
/// <typeparam name="T">Type of the managed state class.</typeparam>
public class StateManager<T> where T : new()
{
private readonly T _state;
private TaskCompletionSource<T> _taskCompletition = new TaskCompletionSource<T>();
private readonly object _taskCompletitionLock = new object();
public StateManager()
{
_state = new T();
}
public void ChangeState(Action<T> updateFunction)
{
lock (_taskCompletitionLock)
{
updateFunction(_state);
_taskCompletition.SetResult(_state);
_taskCompletition = new TaskCompletionSource<T>();
}
}
public Task<T> GetChangedState() => _taskCompletition.Task;
}
Register in Startup.ConfigureServices:
services.AddSingleton<StateManager<State>>();
Usage (in your controller):
public async Task<IActionResult> StateMonitor()
{
var newState = await _stateManager.GetChangedState();
return Ok(newState);
}
public async Task<IActionResult> SetNewState()
{
_stateManager.ChangeState(state => state.MyStateField1 = "My changed State");
return NoContentResult();
}

Async task within MvvmCross Command not returning

I am building a small project using MvvMCross within a Xamarin PCL project and having issue with an async Task that I am calling within a command that is bound to a button.
I have a fake web service where-in I simply call Task.Delay(3000). When the process gets to this point it simply sits and does nothing.
I originally had the command call using the .wait() call but read somewhere that this was a blocking call and cant be miced with "async / wait"
Could someone help and possible give me a hint as to where I am going wrong on the command binding please ?
https://bitbucket.org/johncogan/exevaxamarinapp is the public git repo, the specific command is
public ICommand SaveProfile
within the ProfileViewModel.cs file.
The specific code is:
public ICommand SaveProfile
{
get
{
return new MvxCommand(() =>
{
if (_profile.IsValidData())
{
// Wait for task to compelte, do UI updates here
// TODO Throbber / Spinner
EnumWebServiceResult taskResult;
Mvx.Resolve<IProfileWebService>().SendProfileToServer(_profile).Wait();
if(_profileWebService.getLastResponseResult() == true){
taskResult = EnumWebServiceResult.SUCCESS;
}else{
taskResult = EnumWebServiceResult.FAILED_UNKNOWN;
}
//_profileWebService.SendProfileToServer(_profile).Wait();
// Close(this);
}
});
}
}
The web service class () is:
using System;
using System.Threading.Tasks;
using ExevaXamarinApp.Models;
namespace ExevaXamarinApp.Services
{
public class FakeProfileWebService : IProfileWebService
{
public int _delayPeriod { get; private set; }
public bool? lastResult;
/// <summary>
/// Initializes a new instance of the <see cref="T:ExevaXamarinApp.Enumerations.FakeProfileWebService"/> class.
/// </summary>
/// 3 second delay to simulate a remote request
public FakeProfileWebService()
{
_delayPeriod = 3000;
lastResult = null;
}
private Task Sleep()
{
return Task.Delay(3000);
}
public bool? getLastResponseResult(){
return lastResult;
}
/// <summary>
/// Sends the profile to server asynchronously
/// </summary>
/// <returns>EnumWebServiceResultFlag value</returns>
/// <param name="profileObject">Profile model object</param>
public async Task SendProfileToServer(Profile profileObject)
{
// Validate arguments before attempting to use web serivce
if (profileObject.IsValidData())
{
// TODO: Return ENUM FLAG that represents the state of the result
await Sleep();
lastResult = true;
}else{
lastResult = false;
}
}
}
}
Please try this:
public ICommand SaveProfile
{
get
{
return new MvxCommand(async () => // async added
{
if (_profile.IsValidData())
{
// Wait for task to compelte, do UI updates here
// TODO Throbber / Spinner
EnumWebServiceResult taskResult;
await Mvx.Resolve<IProfileWebService>().SendProfileToServer(_profile).ConfigureAwait(false); // await, confi.. added
if(_profileWebService.getLastResponseResult() == true){
taskResult = EnumWebServiceResult.SUCCESS;
}else{
taskResult = EnumWebServiceResult.FAILED_UNKNOWN;
}
//_profileWebService.SendProfileToServer(_profile).Wait();
// Close(this);
}
});
}
}
private async Task Sleep() // async added
{
return await Task.Delay(3000).ConfigureAwait(false); // await, confi... added
}
public async Task SendProfileToServer(Profile profileObject)
{
// Validate arguments before attempting to use web serivce
if (profileObject.IsValidData())
{
// TODO: Return ENUM FLAG that represents the state of the result
await Sleep().ConfigureAwait(false); // await, confi... added
lastResult = true;
}else{
lastResult = false;
}
}
The problem is, that the context from the UI and the async cause a deadlock.

Expect call is not working on mock

I am writing test for CheckPassWord()
I presume the Expect call is not behaving as expected on my userMangerMock.
//CheckPassword returns true if the parameter matches to the exsting user.
//Existing user is obtained by GetUser() by internal call
bool passWordMatch = userMangerMock.CheckPassword(userInfo.Id, userInfo.Password);
CheckPassWord() internally calls GetUser(),
Since GetUser() needs more deeper internal calls I decided to return a stubUser
I believe implementation of Expect() is sufficient for that.
Note that the following call var userInfo = userMangerMock.GetUser("TestManager");is returning stubUser.
But , CheckPassword() call I am assuming the stubUser is not returned thus the test failing.
Correct me if any bug in the following UT.
//Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
CreateUser();
}
private static IUser _stubUser;
public void CreateUser()
{
IUserFactory iUserFactory = new UserFactory();
UserParams parameters = new UserParams();
parameters.Password = "TestPassword123!";
parameters.UserID = "TestManager";
_stubUser = iUserFactory.CreateUser(parameters);
}
/// <summary>
///A test for CheckPassword
///</summary>
[TestMethod( )]
public void CheckPasswordTest()
{
// !!! Below I've used WhenCalled() to show you that correct
// expectation is called based on argument type, just see in debugger
IUserManager userMangerMock = MockRepository.GenerateMock<IUserManager>();
userMangerMock.Expect(x => x.GetUser(Arg<string>.Is.Anything))
.WhenCalled((mi) =>
{
Debug.WriteLine("IUserManager - string parameter");
})
.Return(_stubUser);
var userInfo = userMangerMock.GetUser("TestManager");
bool passWordMatch = userMangerMock.CheckPassword(userInfo.Id, userInfo.Password);
userMangerMock.VerifyAllExpectations();
Assert.AreEqual(true, passWordMatch);
}
/// <summary>
/// Returns true if password matches the user
/// </summary>
public bool CheckPassword(string userId, string password)
{
if (userId == null)
{
throw new ArgumentNullException("userId");
}
IUser user = GetUser(userId);
if (user == null)
{
throw new UserManagementException(UserManagementError.InvalidUserId);
}
return (user.Password == password);
}
A couple of things I noticed in your test:
userMangerMock.VerifyAllExpectations();
This will always pass since you are manually calling GetUser() in the test code itself:
var userInfo = userMangerMock.GetUser("TestManager");
So you can actually remove this verify call, since it's not needed.
It feels like your unit test does not seem to provide any value to you, since it's asserting on a hard-coded mock object.
var userInfo = userMangerMock.GetUser("TestManager");
bool passWordMatch = userMangerMock.ChePassword(userInfo.Id, userInfo.Password);
Assert.AreEqual(true, passWordMatch);
If userInfo is a reference to the stub object _stubUser then you're unit test can be refactored to:
bool passWordMatch = userMangerMock.CheckPassword(_stubUser.Id, _stubUser.Password);
Assert.AreEqual(true, passWordMatch);

Wrapping ManualResetEvent as awaitable task

I'd like to await on a manual reset event with time-out and observing cancellation. I've come up with something like below. The manual reset event object is provided by an API beyond my control. Is there a way to make this happen without taking on and blocking a thread from ThreadPool?
static Task<bool> TaskFromWaitHandle(WaitHandle mre, int timeout, CancellationToken ct)
{
return Task.Run(() =>
{
bool s = WaitHandle.WaitAny(new WaitHandle[] { mre, ct.WaitHandle }, timeout) == 0;
ct.ThrowIfCancellationRequested();
return s;
}, ct);
}
// ...
if (await TaskFromWaitHandle(manualResetEvent, 1000, cts.Token))
{
// true if event was set
}
else
{
// false if timed out, exception if cancelled
}
[EDITED] Apparently, it makes sense to use RegisterWaitForSingleObject. I'll give it a try.
RegisterWaitForSingleObject will combine waits onto dedicated waiter threads, each of which can wait on multiple handles (specifically, 63 of them, which is MAXIMUM_WAIT_OBJECTS minus one for a "control" handle).
So you should be able to use something like this (warning: untested):
public static class WaitHandleExtensions
{
public static Task AsTask(this WaitHandle handle)
{
return AsTask(handle, Timeout.InfiniteTimeSpan);
}
public static Task AsTask(this WaitHandle handle, TimeSpan timeout)
{
var tcs = new TaskCompletionSource<object>();
var registration = ThreadPool.RegisterWaitForSingleObject(handle, (state, timedOut) =>
{
var localTcs = (TaskCompletionSource<object>)state;
if (timedOut)
localTcs.TrySetCanceled();
else
localTcs.TrySetResult(null);
}, tcs, timeout, executeOnlyOnce: true);
tcs.Task.ContinueWith((_, state) => ((RegisteredWaitHandle)state).Unregister(null), registration, TaskScheduler.Default);
return tcs.Task;
}
}
You also can use SemaphoreSlim.WaitAsync() which is similar to ManualResetEvent
Stephen's Cleary solution looks perfect. Microsoft provides the similar one.
As I haven't seen an example with cancellation logic.
Here it is:
public static class WaitHandleExtensions
{
public static Task WaitOneAsync(this WaitHandle waitHandle, CancellationToken cancellationToken, int timeoutMilliseconds = Timeout.Infinite)
{
if (waitHandle == null)
throw new ArgumentNullException(nameof(waitHandle));
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
CancellationTokenRegistration ctr = cancellationToken.Register(() => tcs.TrySetCanceled());
TimeSpan timeout = timeoutMilliseconds > Timeout.Infinite ? TimeSpan.FromMilliseconds(timeoutMilliseconds) : Timeout.InfiniteTimeSpan;
RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
(_, timedOut) =>
{
if (timedOut)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(true);
}
},
null, timeout, true);
Task<bool> task = tcs.Task;
_ = task.ContinueWith(_ =>
{
rwh.Unregister(null);
return ctr.Unregister();
}, CancellationToken.None);
return task;
}
}
You can give this one a shot, https://www.badflyer.com/asyncmanualresetevent , tried to build upon the example on https://blogs.msdn.com/b/pfxteam/archive/2012/02/11/10266920.aspx to support timeouts and cancellation.
using System;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// An async manual reset event.
/// </summary>
public sealed class ManualResetEventAsync
{
// Inspiration from https://devblogs.microsoft.com/pfxteam/building-async-coordination-primitives-part-1-asyncmanualresetevent/
// and the .net implementation of SemaphoreSlim
/// <summary>
/// The timeout in milliseconds to wait indefinitly.
/// </summary>
private const int WaitIndefinitly = -1;
/// <summary>
/// True to run synchronous continuations on the thread which invoked Set. False to run them in the threadpool.
/// </summary>
private readonly bool runSynchronousContinuationsOnSetThread = true;
/// <summary>
/// The current task completion source.
/// </summary>
private volatile TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>();
/// <summary>
/// Initializes a new instance of the <see cref="ManualResetEventAsync"/> class.
/// </summary>
/// <param name="isSet">True to set the task completion source on creation.</param>
public ManualResetEventAsync(bool isSet)
: this(isSet: isSet, runSynchronousContinuationsOnSetThread: true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ManualResetEventAsync"/> class.
/// </summary>
/// <param name="isSet">True to set the task completion source on creation.</param>
/// <param name="runSynchronousContinuationsOnSetThread">If you have synchronous continuations, they will run on the thread which invokes Set, unless you set this to false.</param>
public ManualResetEventAsync(bool isSet, bool runSynchronousContinuationsOnSetThread)
{
this.runSynchronousContinuationsOnSetThread = runSynchronousContinuationsOnSetThread;
if (isSet)
{
this.completionSource.TrySetResult(true);
}
}
/// <summary>
/// Wait for the manual reset event.
/// </summary>
/// <returns>A task which completes when the event is set.</returns>
public Task WaitAsync()
{
return this.AwaitCompletion(ManualResetEventAsync.WaitIndefinitly, default(CancellationToken));
}
/// <summary>
/// Wait for the manual reset event.
/// </summary>
/// <param name="token">A cancellation token.</param>
/// <returns>A task which waits for the manual reset event.</returns>
public Task WaitAsync(CancellationToken token)
{
return this.AwaitCompletion(ManualResetEventAsync.WaitIndefinitly, token);
}
/// <summary>
/// Wait for the manual reset event.
/// </summary>
/// <param name="timeout">A timeout.</param>
/// <param name="token">A cancellation token.</param>
/// <returns>A task which waits for the manual reset event. Returns true if the timeout has not expired. Returns false if the timeout expired.</returns>
public Task<bool> WaitAsync(TimeSpan timeout, CancellationToken token)
{
return this.AwaitCompletion((int)timeout.TotalMilliseconds, token);
}
/// <summary>
/// Wait for the manual reset event.
/// </summary>
/// <param name="timeout">A timeout.</param>
/// <returns>A task which waits for the manual reset event. Returns true if the timeout has not expired. Returns false if the timeout expired.</returns>
public Task<bool> WaitAsync(TimeSpan timeout)
{
return this.AwaitCompletion((int)timeout.TotalMilliseconds, default(CancellationToken));
}
/// <summary>
/// Set the completion source.
/// </summary>
public void Set()
{
if (this.runSynchronousContinuationsOnSetThread)
{
this.completionSource.TrySetResult(true);
}
else
{
// Run synchronous completions in the thread pool.
Task.Run(() => this.completionSource.TrySetResult(true));
}
}
/// <summary>
/// Reset the manual reset event.
/// </summary>
public void Reset()
{
// Grab a reference to the current completion source.
var currentCompletionSource = this.completionSource;
// Check if there is nothing to be done, return.
if (!currentCompletionSource.Task.IsCompleted)
{
return;
}
// Otherwise, try to replace it with a new completion source (if it is the same as the reference we took before).
Interlocked.CompareExchange(ref this.completionSource, new TaskCompletionSource<bool>(), currentCompletionSource);
}
/// <summary>
/// Await completion based on a timeout and a cancellation token.
/// </summary>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>A task (true if wait succeeded). (False on timeout).</returns>
private async Task<bool> AwaitCompletion(int timeoutMS, CancellationToken token)
{
// Validate arguments.
if (timeoutMS < -1 || timeoutMS > int.MaxValue)
{
throw new ArgumentException("The timeout must be either -1ms (indefinitely) or a positive ms value <= int.MaxValue");
}
CancellationTokenSource timeoutToken = null;
// If the token cannot be cancelled, then we dont need to create any sort of linked token source.
if (false == token.CanBeCanceled)
{
// If the wait is indefinite, then we don't need to create a second task at all to wait on, just wait for set.
if (timeoutMS == -1)
{
return await this.completionSource.Task;
}
timeoutToken = new CancellationTokenSource();
}
else
{
// A token source which will get canceled either when we cancel it, or when the linked token source is canceled.
timeoutToken = CancellationTokenSource.CreateLinkedTokenSource(token);
}
using (timeoutToken)
{
// Create a task to account for our timeout. The continuation just eats the task cancelled exception, but makes sure to observe it.
Task delayTask = Task.Delay(timeoutMS, timeoutToken.Token).ContinueWith((result) => { var e = result.Exception; }, TaskContinuationOptions.ExecuteSynchronously);
var resultingTask = await Task.WhenAny(this.completionSource.Task, delayTask).ConfigureAwait(false);
// The actual task finished, not the timeout, so we can cancel our cancellation token and return true.
if (resultingTask != delayTask)
{
// Cancel the timeout token to cancel the delay if it is still going.
timeoutToken.Cancel();
return true;
}
// Otherwise, the delay task finished. So throw if it finished because it was canceled.
token.ThrowIfCancellationRequested();
return false;
}
}
}
Alternative solution: wait for the handles of the task and the manual reset event
I was having memory leaks when using Task.WaitAny() with a Task (returned by SqlConnection.OpenAsync()') and a Manual Reset Event received as parameter and wrapped in a Task with AsTask(). These object were not being disposed: TaskCompletionSource<Object>, Task<Object>, StandardTaskContinuation, RegisteredWaitHandle, RegisteredWaithandleSafe, ContinuationResultTaskFromresultTask<Object,bool>, _ThreadPoolWaitOrTimerCallback).
This is real production code, used in a Windows service, of a function that tries to open a connection to a db in a loop until the connection is opened, or the operation fails, or the ManualResetEvent _finishRequest, received as parameter in the function containing this code, is signaled by code in any other thread.
To avoid the leak, I decided to do it the other way round: wait for the handles of the _finishRequest and the Task returned by OpenAsync():
Task asyncOpening = sqlConnection.OpenAsync();
// Wait for the async open to finish, or until _finishRequest is signaled
var waitHandles = new WaitHandle[]
{
// index 0 in array: extract the AsyncWaitHandle from the Task
((IAsyncResult)asyncOpening).AsyncWaitHandle,
// index 1:
_finishRequest
};
// Check if finish was requested (index of signaled handle in the array = 1)
int whichFinished = WaitHandle.WaitAny(waitHandles);
finishRequested = whichFinished == 1;
// If so, break the loop to exit immediately
if (finishRequested)
break;
// If not, check if OpenAsync finished with error (it's a Task)
if (asyncOpening.IsFaulted)
{
// Extract the exception from the task, and throw it
// NOTE: adapt it to your case. In mine, I'm interested in the inner exception,
// but you can check the exception itself, for example to see if it was a timeout,
// if you specified it in the call to the async function that returns the Task
var ex = asyncOpening?.Exception?.InnerExceptions?[0];
if (ex != null) throw ex;
}
else
{
Log.Verbose("Connection to database {Database} on server {Server}", database, server);
break;
}
If you also need the timeout, you can include it in the call to OpenAsync, or you asyn function, and then check if the result of the async operation was cancelled because of the timeout: check the status of the Task when finished, as you can see in the NOTE in the code comment.

Simulate a delay in execution in Unit Test using Moq

I'm trying to test the following:
protected IHealthStatus VerifyMessage(ISubscriber destination)
{
var status = new HeartBeatStatus();
var task = new Task<CheckResult>(() =>
{
Console.WriteLine("VerifyMessage(Start): {0} - {1}", DateTime.Now, WarningTimeout);
Thread.Sleep(WarningTimeout - 500);
Console.WriteLine("VerifyMessage(Success): {0}", DateTime.Now);
if (CheckMessages(destination))
{
return CheckResult.Success;
}
Console.WriteLine("VerifyMessage(Pre-Warning): {0} - {1}", DateTime.Now, ErrorTimeout);
Thread.Sleep(ErrorTimeout - 500);
Console.WriteLine("VerifyMessage(Warning): {0}", DateTime.Now);
if (CheckMessages(destination))
{
return CheckResult.Warning;
}
return CheckResult.Error;
});
task.Start();
task.Wait();
status.Status = task.Result;
return status;
}
with the following unit test:
public void HeartBeat_Should_ReturnWarning_When_MockReturnsWarning()
{
// Arrange
var heartbeat = new SocketToSocketHeartbeat(_sourceSubscriber.Object, _destinationSubscriber.Object);
heartbeat.SetTaskConfiguration(this.ConfigurationHB1ToHB2_ValidConfiguration());
// Simulate the message being delayed to destination subscriber.
_destinationSubscriber.Setup(foo => foo.ReceivedMessages).Returns(DelayDelivery(3000, Message_HB1ToHB2()));
// Act
var healthStatus = heartbeat.Execute();
// Assert
Assert.AreEqual(CheckResult.Warning, healthStatus.Status);
}
Message_HB1ToHB2() just returns a string of characters and the "Delay Delivery" method is
private List<NcsMessage> DelayDelivery(int delay, string message)
{
var sent = DateTime.Now;
var msg = new NcsMessage()
{
SourceSubscriber = "HB1",
DestinationSubscriber = "HB2",
SentOrReceived = sent,
Message = message
};
var messages = new List<NcsMessage>();
messages.Add(msg);
Console.WriteLine("DelayDelivery: {0}", DateTime.Now);
Thread.Sleep(delay);
Console.WriteLine("DelayDelivery: {0}", DateTime.Now);
return messages;
}
I'm using Moq as the mocking framework and MSTest as the testing framework. Whenever I run the unit test, I get the following output:
DelayDelivery: 04/04/2013 15:50:33
DelayDelivery: 04/04/2013 15:50:36
VerifyMessage(Start): 04/04/2013 15:50:36 - 3000
VerifyMessage(Success): 04/04/2013 15:50:38
Beyond the obvious "code smell" using the Thread.Sleep in the methods above, the result of the unit test is not what I'm trying to accomplish.
Can anyone suggest a better/accurate way to use the Moq framework to simulate a delay in "delivery" of the message. I've left out some of the "glue" code and only included the relevant parts. Let me know if something I've left out that prevents you from being able to understand the question.
If you want a Moq mock to just sit and do nothing for a while you can use a callback:
Mock<IFoo> mockFoo = new Mock<IFoo>();
mockFoo.Setup(f => f.Bar())
.Callback(() => Thread.Sleep(1000))
.Returns("test");
string result = mockFoo.Object.Bar(); // will take 1 second to return
Assert.AreEqual("test", result);
I've tried that in LinqPad and if you adjust the Thread.Sleep() the execution time varies accordingly.
When you setup your mock you can tell the thread to sleep in the return func:
Mock<IMyService> myService = new Mock<IMyService>();
myService.Setup(x => x.GetResultDelayed()).Returns(() => {
Thread.Sleep(100);
return "result";
});
If running asynchronous code, Moq has the ability to delay the response with the second parameter via a TimeSpan
mockFooService
.Setup(m => m.GetFooAsync())
.ReturnsAsync(new Foo(), TimeSpan.FromMilliseconds(500)); // Delay return for 500 milliseconds.
If you need to specify a different delay each time the method is called, you can use .SetupSequence like
mockFooService
.SetupSequence(m => m.GetFooAsync())
.Returns(new Foo())
.Returns(Task.Run(async () =>
{
await Task.Delay(500) // Delay return for 500 milliseconds.
return new Foo();
})
I could not get Moq version to work, so I ended up making something like this:
a small example using WaitHandle:
[TestFixture]
public class EventWaitHandleTests
{
class Worker {
private volatile bool _shouldStop;
public EventWaitHandle WaitHandleExternal;
public void DoWork ()
{
while (!_shouldStop)
{
Console.WriteLine("worker thread: working...");
Thread.Sleep(1000);
WaitHandleExternal.Set();
}
}
public void RequestStop()
{
_shouldStop = true;
}
}
[Test]
public void WaitForHandleEventTest()
{
EventWaitHandle _waitHandle = new AutoResetEvent (false); // is signaled value change to true
// start a thread which will after a small time set an event
Worker workerObject = new Worker ();
workerObject.WaitHandleExternal = _waitHandle;
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start();
Console.WriteLine ("Waiting...");
_waitHandle.WaitOne(); // Wait for notification
Console.WriteLine ("Notified");
// Stop the worker thread.
workerObject.RequestStop();
}
}
I like and voted for serup's solution. My answer is a version of his converted for use as a library.
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
/// <summary>
/// support halting a workflow and waiting for a finish request
/// </summary>
public class MockWorker
{
private readonly DateTime? _end;
private volatile bool _shouldStop;
/// <summary>
/// Create a worker object
/// </summary>
/// <param name="timeoutInMilliseconds">How long before DoWork will timeout. default - Null will not timeout.</param>
public MockWorker(int? timeoutInMilliseconds = null)
{
if (timeoutInMilliseconds.HasValue)
_end = DateTime.Now.AddMilliseconds(timeoutInMilliseconds.Value);
}
/// <summary>
/// Instruct DoWork to complete
/// </summary>
public void RequestStop()
{
_shouldStop = true;
}
/// <summary>
/// Do work async will run until either timeoutInMilliseconds is exceeded or RequestStop is called.
/// </summary>
public async Task DoWorkAsync()
{
while (!_shouldStop)
{
await Task.Delay(100);
if (_end.HasValue && _end.Value < DateTime.Now)
throw new AssertFailedException("Timeout");
}
}
/// <summary>
/// Do work async will run until either timeoutInMilliseconds is exceeded or RequestStop is called.
/// </summary>
/// <typeparam name="T">Type of value to return</typeparam>
/// <param name="valueToReturn">The value to be returned</param>
/// <returns>valueToReturn</returns>
public async Task<T> DoWorkAsync<T>(T valueToReturn)
{
await DoWorkAsync();
return valueToReturn;
}
}
I had a similiar situation, but with an Async method. What worked for me was to do the following:
mock_object.Setup(scheduler => scheduler.MakeJobAsync())
.Returns(Task.Run(()=> { Thread.Sleep(50000); return Guid.NewGuid().ToString(); }));

Categories