Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Unit Testing a method containing MainThread.GetMainThreadSynchronizationContextAsync()

Using xunit, I test a method calling which is the Xamarin.Essentials method MainThread.GetMainThreadSynchronizationContextAsync(). I added the Xamarin.Essentials nuget to my test project as well.

But I still get an error from Xamarin.Essentials:

Xamarin.Essentials.NotImplementedInReferenceAssemblyException : This functionality is not implemented in the portable version of this assembly. You should reference the NuGet package from your main application project in order to reference the platform-specific implementation.

Is there a way to get this to work?

An **alternative **I tried is to hide the call MainThread.GetMainThreadSynchronizationContextAsync() behind an interface to be able to mock it away in the unit test. But then I get into trouble cause System.Reactive is complaining a ArgumentNullException in the SynchronizationContext I receive from XUnit.

// raises ArgumentException in System.Reactive ObserveOn(context)
appCtxMock.Setup(_ => _.GetMainThreadContext()).ReturnsAsync(SynchronizationContext.Current);

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai
    edited November 2019

    Xamarin.Essentials requires platform-specific setup. Have you added the initialzation method on platform projects like

    For Android.

    protected override void OnCreate(Bundle savedInstanceState) {
        //...
        base.OnCreate(savedInstanceState);
        Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
    }
    

    A similar issue case you can refer to:
    https://docs.microsoft.com/en-us/xamarin/essentials/get-started?context=xamarin/android&tabs=windows,android

  • thisismyselfthisismyself Member ✭✭

    I run the code on Windows 10, using xunit test runner. Thus Android initialization is not applicable here. I thought to try UWP (also not really correct) initialization, but the link you provided states it is no initialization required for UWP.

  • NMackayNMackay GBInsider, University admin

    https://github.com/jonathanpeppers/Xamarin.Forms.Mocks
    https://www.nuget.org/packages/Xamarin.Essentials.Interfaces/

    We use Xamarin Essential Interfaces and just inject the interfaces into out VM's , that way we can mock the essentials services.

    If you must test stuff buried in your viewmodel that requires Forms then use Xamarin Forms Mocks (Device.BeginInvokeOnMainThread) for example would require Forms Mocks to be initialised.

  • thisismyselfthisismyself Member ✭✭

    @NMackay This is really nice there are already interfaces for this, thanks for the links!

    Anyway: As mentioned in my original post, I already tried to go the way of mocking the Xamarin Essential Interface. So I added the method SynchronizationContext GetMainThreadContext() to my interface IAppContext where I use to centralize wide-spread used stuff. But then I could not figure out how to setup the mock correct. I tried following in xunit test project:

    // raises ArgumentException in System.Reactive ObserveOn(context)
    appCtxMock.Setup(_ => _.GetMainThreadContext()).ReturnsAsync(SynchronizationContext.Current);
    

    But then I had a NullReferenceException in System.Reactive ObserveOn method, where I passed the SychronizationContext. Possibly there is an error in System.Reactive. Or I use it wrong. Anyway: Due to some architectural changes I do not need a solution to this now and I am afraid I will not find time to investigate further - until red tests hit me again...

Sign In or Register to comment.