dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.6k stars 1.03k forks source link

🐞 NullReferenceException in Maui UnitTests #40955

Open MarkusRodler opened 1 month ago

MarkusRodler commented 1 month ago

Describe the bug

After upgrading .NET 8 to the newest version and installing the newly required workloads? wasi-experimental, maui-tizen and updating maui-android the unit tests stopped working. Disclaimer: I don't need any maui-tizen package. We have no reference to it in our codebase. It may depend on the new .NET 8 version or on the workloads. IDK

To Reproduce

  1. Create new Maui project from scratch
  2. Write basic unit test for the App.xaml.cs like that:
    
    namespace Test;

[TestClass] public class AppTest { Maui.App? sut;

[TestInitialize]
public void Initialize() => sut = new();

[TestCleanup]
public void Cleanup() => Application.Current = null;

[TestMethod]
public void CanBeCreated() => Assert.IsNotNull(sut);

}


### Exceptions (if any)
```bash
MSBuild version 17.10.4+10fbfbf2e for .NET
    Determining projects to restore...
    Restored /home/dark/Workspace/Mrd/mrd-wetter-app/Test/Test.csproj (in 1.21 sec).
    Restored /home/dark/Workspace/Mrd/mrd-wetter-app/Shared/Shared.csproj (in 1.24 sec).
    Restored /home/dark/Workspace/Mrd/mrd-wetter-app/Maui/Maui.csproj (in 1.5 sec).
    Restored /home/dark/Workspace/Mrd/mrd-wetter-app/Client/Client.csproj (in 3.69 sec).
    Shared -> /home/dark/Workspace/Mrd/mrd-wetter-app/Shared/bin/Debug/net8.0/Shared.dll
    Client -> /home/dark/Workspace/Mrd/mrd-wetter-app/Client/bin/Debug/net8.0/Client.dll
    Client (Blazor output) -> /home/dark/Workspace/Mrd/mrd-wetter-app/Client/bin/Debug/net8.0/wwwroot
    Maui -> /home/dark/Workspace/Mrd/mrd-wetter-app/Maui/bin/Debug/net8.0/Maui.dll
    Test -> /home/dark/Workspace/Mrd/mrd-wetter-app/Test/bin/Debug/net8.0/Test.dll
    [coverlet] _mapping file name: 'CoverletSourceRootsMapping_Test'
  Test run for /home/dark/Workspace/Mrd/mrd-wetter-app/Test/bin/Debug/net8.0/Test.dll (.NETCoreApp,Version=v8.0)
  Microsoft (R) Test Execution Command Line Tool Version 17.10.0 (x64)
  Copyright (c) Microsoft Corporation.  All rights reserved.

  Starting test execution, please wait...
  A total of 1 test files matched the specified pattern.
    Failed CanBeCreated [62 ms]
EXEC : error Message:  [/home/dark/Workspace/Mrd/mrd-wetter-app/Test/Test.csproj]
     Initialization method Test.AppTest.Initialize threw exception. System.NullReferenceException: Object reference not set to an instance of an object..
    Stack Trace:
        at Microsoft.Maui.Controls.Application.<.ctor>b__7_0()
     at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
     at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
     at System.Lazy`1.CreateValue()
     at Microsoft.Maui.Controls.Application.get_SystemResources()
     at Microsoft.Maui.Controls.ResourcesExtensions.GetMergedResources(IElementDefinition element)
     at Microsoft.Maui.Controls.Application.set_MainPage(Page value)
     at Maui.App..ctor() in /home/dark/Workspace/Mrd/mrd-wetter-app/Maui/App.xaml.cs:line 8
     at Test.AppTest.Initialize() in /home/dark/Workspace/Mrd/mrd-wetter-app/Test/Maui/AppTest.cs:line 9
     at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
     at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed!  - Failed:     1, Passed:    0, Skipped:     0, Total:    1, Duration: 142 ms - Test.dll (net8.0)
/home/dark/Workspace/Mrd/mrd-wetter-app/Test/Test.csproj(24,9): error MSB3073: The command "dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:ExcludeByFile=\"**/Program.cs,**/MauiProgram.cs,**/ExceptionHandler.cs,**/*.razor,**/*.g.cs\"" exited with code 1.

 *  Der Terminalprozess "dotnet 'msbuild', 'Test', '/t:testmsbuild', '/property:GenerateFullPaths=true', '/consoleloggerparameters:NoSummary'" wurde mit folgendem Exitcode beendet: 1. 

Further technical details

Runtime Environment: OS Name: debian OS Version: 12 OS Platform: Linux RID: linux-x64 Base Path: /usr/share/dotnet/sdk/8.0.300/

.NET workloads installed: [maui-android] Installation Source: SDK 8.0.300 Manifest Version: 8.0.21/8.0.100 Manifest Path: /usr/share/dotnet/sdk-manifests/8.0.100/microsoft.net.sdk.maui/8.0.21/WorkloadManifest.json Install Type: FileBased

[maui-tizen] Installation Source: SDK 8.0.300 Manifest Version: 8.0.21/8.0.100 Manifest Path: /usr/share/dotnet/sdk-manifests/8.0.100/microsoft.net.sdk.maui/8.0.21/WorkloadManifest.json Install Type: FileBased

[wasi-experimental] Installation Source: SDK 8.0.300 Manifest Version: 8.0.5/8.0.100 Manifest Path: /usr/share/dotnet/sdk-manifests/8.0.100/microsoft.net.workload.mono.toolchain.current/8.0.5/WorkloadManifest.json Install Type: FileBased

Host: Version: 8.0.5 Architecture: x64 Commit: 087e15321b

.NET SDKs installed: 6.0.422 [/usr/share/dotnet/sdk] 7.0.409 [/usr/share/dotnet/sdk] 8.0.300 [/usr/share/dotnet/sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 6.0.30 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.19 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.5 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.30 [/usr/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.19 [/usr/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.5 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

- The IDE (VS / VS Code/ VS4Mac) you're running on, and its version: Doesn't matter. 
- Operating Systems: debian / windows.

Previous dotnet version:
```sh
dotnet --version
8.0.204

Previous workloads:

dotnet workload list

Installed Workload Id      Manifest Version      Installation Source
--------------------------------------------------------------------
maui-android               8.0.7/8.0.100         SDK 8.0.200        

Use `dotnet workload search` to find additional workloads to install.

After .NET upgrade wasi-experimental is now needed?:

dotnet workload restore
Installing workloads: wasi-experimental

After that maui-tizen is now needed?:

dotnet workload restore
Installing workloads: maui-tizen maui-android
MichaelLHerman commented 1 week ago

Workaround - provide the dependency?

If you're using Moq, add this in a OneTimeSetup / ClassInitialize

DependencyService.RegisterSingleton(Mock.Of<ISystemResourcesProvider>(x =>
                x.GetSystemResources() == Mock.Of<IResourceDictionary>(d =>
                    d.GetEnumerator() == Enumerable.Empty<KeyValuePair<string, object>>().GetEnumerator())));

Without Moq:

        [ClassInitialize]
        public static void SetupApplication()
        {
            DependencyService.RegisterSingleton<ISystemResourcesProvider>(new MockSystemResourcesProvider());
        }

        internal class MockSystemResourcesProvider : ISystemResourcesProvider
        {
            public IResourceDictionary GetSystemResources() => new MockResourceDictionary();
        }

        internal class MockResourceDictionary : List<KeyValuePair<string, object>>, IResourceDictionary
        {
            public bool TryGetValue(string key, out object value) => throw new NotImplementedException();

            public event EventHandler<ResourcesChangedEventArgs> ValuesChanged;
        }