unexpected async await behavior in mstest unit test - testing

I'm having newbie problems testing an async method. I've read a few other posts, including How to correct write test with async methods?, and I think I'm doing things correctly, but I'm clearly missing something.
Here's the code I'm trying to test:
/// <summary>
/// Temporary method used to simulate the time required to generate a report.
/// </summary>
public virtual async Task GenerateTestReportAsync()
{
++ActiveTaskCounter;
await Task.Delay(2000);
--ActiveTaskCounter;
}
And here's the test (yes, I could/should improve it by storing the ActiveTaskCounter values in a list, but that's beside the point):
[TestMethod]
public async Task GenerateTestReportAsyncUpdatesActiveTaskCounter()
var bayViewModel = CreateBayViewModel();
var invocationCount = 0;
bayViewModel.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "ActiveTaskCounter")
{
++invocationCount;
}
};
await bayViewModel.GenerateTestReportAsync();
//Thread.Sleep(2100); // TODO: Why is this needed?
Assert.AreEqual(2, invocationCount);
Assert.AreEqual(0, bayViewModel.ActiveTaskCounter);
}
The test always passes with the Thread.Sleep uncommented. It always fails with the Thread.Sleep commented, as shown above. Why is this? I assumed the code below the "await bayViewModel.GenerateTestReportAsync()" wouldn't even execute until GenerateTestReportAsync was really finished.
BTW, I'm using:
Microsoft Visual Studio Ultimate 2012
Version 11.0.51106.01 Update 1
Microsoft .NET Framework
Version 4.5.50709
Thanks for any help you can provide! This has me stumped :-|
EDIT: Here's a minimal repro of the view model class...
using System.ComponentModel;
using System.Threading.Tasks;
public class BayViewModel : INotifyPropertyChanged
{
public BayViewModel()
{
PropertyChanged = (sender, args) => { };
}
public event PropertyChangedEventHandler PropertyChanged;
private int _activeTaskCounter;
public int ActiveTaskCounter
{
get
{
return _activeTaskCounter;
}
set
{
_activeTaskCounter = value;
PropertyChanged(this, new PropertyChangedEventArgs("ActiveTaskCounter"));
}
}
public virtual async Task GenerateTestReportAsync()
{
++ActiveTaskCounter;
await Task.Delay(2000);
--ActiveTaskCounter;
}
}

Related

Calling javascript from Blazor results in error

I have a Blazor app built on .NET Core 3.1 and I need to be able to access USB port resources. I keep getting the error:
JavaScript interop calls cannot be issued at this time. This is
because the component is being statically rendererd. When prerendering
is enabled, JavaScript interop calls can only be performed during the
OnAfterRenderAsync lifecycle method.
I have a pretty simple Blazor component wrapping the Blazor.Extensions.WebUSB library
public partial class Recordings : ComponentBase
{
[Inject] private IUSB _usb { get; set; }
[Inject] private ILogger<Recordings> _logger { get; set; }
[Inject] private IJSRuntime _runtime { get; set; }
private bool _initialized = false;
protected override Task OnAfterRenderAsync(bool firstRender)
{
if (!_initialized)
{
this._usb.OnConnect += OnConnect;
this._usb.OnDisconnect += OnDisconnect;
this._usb.Initialize();
this._initialized = true;
}
return Task.CompletedTask;
}
protected async Task GetDevices()
{
var devices = await this._usb.GetDevices();
if (devices != null && devices.Length > 0)
{
_logger.LogInformation("Device list received");
}
}
private void OnConnect(USBDevice device)
{
this._logger.LogInformation("Device connected");
}
private void OnDisconnect(USBDevice device)
{
this._logger.LogInformation("Device disconnected");
}
}
And even though I'm doing the JS interop in the OnAfterRenderAsync as suggested I still get the same error. I've tried delaying the call to _usb.Initialize until a button is pressed (meaning the component should definitely have finished rendering.
I've tried disabling prerendering by setting the render-mode attribute in _Host.cshtml to Server instead of ServerPrerendered but nothing changed.
Your code should be like this:
protected override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
this._usb.OnConnect += OnConnect;
this._usb.OnDisconnect += OnDisconnect;
this._usb.Initialize();
this._initialized = true;
}
return Task.CompletedTask;
}
Note: When the firstRender variable is true, which occurs only once, you can use JSInterop. Before that you can't. This is the right time and place to initialize your JavaScript objects.
The OnAfterRender(Boolean) and OnAfterRenderAsync(Boolean) lifecycle methods are useful for performing interop, or interacting with values recieved from #ref. Use the firstRender parameter to ensure that initialization work is only performed once.
Hope this helps...

Pass data from android service to ContentPage in Xamarin Form based application

I am having one Application based on XamarinForms.
One background service I have created in Android project and that service would like to send data to ContentPage(which is in PCL) which is displayed to user.
How could I pass data to ContentPage(From xx.Droid project to PCL)?
One solution is:
To Create class in PCL with static variable(e.g. var TEMP_VAR), which will be accessed from xxx.Droid project.
Update value of that static variable(TEMP_VAR) from the service class from the xxx.Droid project.
Need to create Notifier on that static variable(TEMP_VAR)
Update the content page using MessageCenter Mechanism if require.
If there is any better solution, could you please provide me?
This can be achieved using the concept of C#
Dependency service
Event
Need to have 4 classes for such an implementation:
Interface in PCL(e.g. CurrentLocationService.cs) with event handlers defined in it.
namespace NAMESPACE
{
public interface CurrentLocationService
{
void start();
event EventHandler<PositionEventArgs> positionChanged;
}
}
Implementation of interface of PCL in xxx.Droid project (e.g. CurrentLocationService_Android.cs) using Dependency service
class CurrentLocationService_Android : CurrentLocationService
{
public static CurrentLocationService_Android mySelf;
public event EventHandler<PositionEventArgs> positionChanged;
public void start()
{
mySelf = this;
Forms.Context.StartService(new Intent(Forms.Context, typeof(MyService)));
}
public void receivedNewPosition(CustomPosition pos)
{
positionChanged(this, new PositionEventArgs(pos));
}
}
ContentPage in PCL - which will have object of implementation of interface.
Object can be obtained by
public CurrentLocationService LocationService
{
get
{
if(currentLocationService == null)
{
currentLocationService = DependencyService.Get<CurrentLocationService>();
currentLocationService.positionChanged += OnPositionChange;
}
return currentLocationService;
}
}
private void OnPositionChange(object sender, PositionEventArgs e)
{
Debug.WriteLine("Got the update in ContentPage from service ");
}
Background service in xxx.Droid project. This service will have reference of implementation of dependency service CurrentLocationService.cs
[Service]
public class MyService : Service
{
public string TAG = "MyService";
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
Log.Debug(TAG, TAG + " started");
doWork();
return StartCommandResult.Sticky;
}
public void doWork()
{
var t = new Thread(
() =>
{
Log.Debug(TAG, "Doing work");
Thread.Sleep(10000);
Log.Debug(TAG, "Work completed");
if(CurrentLocationService_Android.mySelf != null)
{
CustomPosition pos = new CustomPosition();
pos.update = "Finally value is updated";
CurrentLocationService_Android.mySelf.receivedNewPosition(pos);
}
StopSelf();
});
t.Start();
}
}
Note : PositionEventArgs class need to be created as per usage to pass on data between service and ContentPage.
This works for me like charm.
Hope so this would be helpful to you.

How to test an NServiceBus handler that uses Schedule

I'm playing with a simple handler that implements IWantToRunWhenBusStartsAndStops and in the start, it schedules a task like so:
public void Start()
{
_schedule.Every(TimeSpan.FromSeconds(5), Moo);
}
_schedule is injected via the constructor. The test I'm trying write is to make sure the task is scheduled when the handler starts. But I can't find a way to mock Schedule as it doesn't have a no-arg constructor and it doesn't implement an interface. I tried creating an actual instance of it with a mocked IBuilder but can't figure out what expectations to set on the IBuilder. Also, I looked at the source to see how they were testing Schedule but it looks like we're on an earlier version (v5.0.0 via nuget) because we don't have a DefaultScheduler which appears to be what they use in their current tests.
In fact NServiceBus team has already covered the scheduler with unit/acceptance test, i.e. there is no need to check whether the task was actually scheduled when your handler is executed. Instead you would probably want to unit test your handler itself, thus check if call to scheduler.Every() has been made. Here is simple example of how your unit test might look like:
[TestClass]
public class Tests
{
[TestMethod]
public void When_executing_handler_the_task_should_be_scheduled()
{
//arrange
var scheduler = new FakeSheduler();
//act
var handler = new TestHandler(scheduler);
handler.Start();
//assert
Assert.IsTrue(scheduler.WasCalled);
}
}
The handler itself:
class TestHandler: IWantToRunWhenBusStartsAndStops
{
readonly IMyScheduler _scheduler;
public TestHandler(IMyScheduler scheduler)
{
_scheduler = scheduler;
}
public void Start()
{
_scheduler.Every(TimeSpan.FromSeconds(5), () => { });
}
public void Stop() { }
}
Finally, you have to abstract from direct usage of NServiceBus scheduler in order to make it testable, here is the idea:
interface IMyScheduler
{
void Every(TimeSpan interval, Action action);
}
//your real implementation
class MySheduler: IMyScheduler
{
readonly Schedule _schedule;
public MySheduler(Schedule schedule)
{
_schedule = schedule;
}
public void Every(TimeSpan interval, Action action)
{
_schedule.Every(TimeSpan.FromSeconds(5), () => { });
}
}
//fake for the testing
class FakeSheduler: IMyScheduler
{
public bool WasCalled { get; set; }
public void Every(TimeSpan interval, Action action)
{
WasCalled = true;
}
}

Duplex services / Singleton class with background thread

I'm wondering if anyone can help me. I have a wcf service running over TCP which will make use of a duplex service. currently this service calls a business object which in turn does some processing. While this processing is happening on a background thread I wish the UI to be updated at certain points. I've attached my code below. TestStatus should be broken up into six parts and the service should update the windows forms UI each time this changes.
The class Scenariocomponent is a singleton (following).
public void BeginProcessingPendingTestCases()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessPendingTestCases));
}
public void BeginProcessingPendingTestCases()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessPendingTestCases));
}
private void ProcessPendingTestCases(object state)
{
while (this.IsProcessingScenarios)
{
ProcessNextPendingTestCase();
}
}
private void ProcessNextPendingTestCase()
{
while (this.ServiceStatus == Components.ServiceStatus.Paused)
{
//Wait.
}
var testOperation = this.PendingTestCases.Dequeue();
if (testOperation.OperationStatus == TestStatus.Pending)
{
throw new NotImplementedException(); //TODO : Handle test.
if (testOperation.OperationStatus != TestStatus.Failed)
{
testOperation.OperationStatus = TestStatus.Processed;
}
this.CompletedTestCases.Enqueue(testOperation);
}
}
Initially I was using MSMQ to update the UI as it worked sufficiently however this is no longer acceptable due to client restrictions.
My Service is as follows:
public class TestHarnessService : ITestHarnessService
{
public bool Ping()
{
return true;
}
public bool IsProcessingScenarios()
{
return ScenarioComponent.Instance.IsProcessingScenarios;
}
public void BeginProcessingScenarios(string xmlDocument, Uri webServiceUri)
{
var doc = new XmlDocument();
doc.LoadXml(xmlDocument);
var scenarios = ScenarioComponent.Deserialize(doc);
ScenarioComponent.Instance.EnqueueScenarioCollection(scenarios, webServiceUri);
ScenarioComponent.Instance.BeginProcessingPendingTestCases();
}
public void ValidateScenarioDocument(string xmlDocument)
{
var doc = new XmlDocument();
doc.LoadXml(xmlDocument);
ScenarioComponent.ValidateScenarioSchema(doc);
}
ITestOperationCallBack Callback
{
get
{
return OperationContext.Current.GetCallbackChannel<ITestOperationCallBack>();
}
}
Now I need the UI to update each time a testoperation changes or completes but I am unsure how to accomplish this. Any feedback would be greatly appreciated.
Thank you!
Instead of using WinForms, you could use WPF and binding, which would handle the updating for you.

CodeCampServer don't input any logging from NHibernate?

Are you ever succeed input NHibernate logging using CodeCampServer architecture?
I read this and I did everything that I can. Maybe there is know problem in this architecture.
I using Infrastructure.NHibernate.DataAccess.Bases.Logger.EnsureInitialized();
to initialize log4net. here the code:
public class DependencyRegistrar
{
private static bool _dependenciesRegistered;
private static void RegisterDependencies()
{
ObjectFactory.Initialize(x => x.Scan(y =>
{
y.AssemblyContainingType<DependencyRegistry>();
y.AssemblyContainingType<NaakRegistry>();
y.LookForRegistries();
y.AddAllTypesOf<IRequiresConfigurationOnStartup>();
}));
new InitiailizeDefaultFactories().Configure();
}
private static readonly object sync = new object();
internal void ConfigureOnStartup()
{
Infrastructure.NHibernate.DataAccess.Bases.Logger.EnsureInitialized();
RegisterDependencies();
var dependenciesToInitialized = ObjectFactory.GetAllInstances<IRequiresConfigurationOnStartup>();
foreach (var dependency in dependenciesToInitialized)
{
dependency.Configure();
}
}
public static T Resolve<T>()
{
return ObjectFactory.GetInstance<T>();
}
public static object Resolve(Type modelType)
{
return ObjectFactory.GetInstance(modelType);
}
public static bool Registered(Type type)
{
EnsureDependenciesRegistered();
return ObjectFactory.GetInstance(type) != null;
}
public static void EnsureDependenciesRegistered()
{
if (!_dependenciesRegistered)
{
lock (sync)
{
if (!_dependenciesRegistered)
{
RegisterDependencies();
_dependenciesRegistered = true;
}
}
}
}
}
And I see the logging files, I can't delete them when the app run, so I know they are generated. in addition, when I log for test, the log are input. For example, this code do input log.
Bases.Logger.Debug(this, "Debug test!")
So, do CodeCampServer have a architecture problem with log4net?
The post looks correct to me.
Are you sure you added the necessary assembly level attribute?
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
If this won't work maybe you should try:
log4net.Config.XmlConfigurator.Configure();
for example in your Application_Start of Global.asax.
If this won't work please post your example code.
Accidentally found solution by replacing the reference forlog4net.dll to the on that come with NHibernate bins, instead the own log4net.
Wired, but I have logs... :)