Description
openedon Aug 13, 2024
Description
When trying to run unit tests and using the MauiAppBuilder after resolving the Application and while creating the Window a NullReferenceException is encountered.
Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
<.ctor>b__7_0()
Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
Lazy`1.CreateValue()
Application.get_SystemResources()
ResourcesExtensions.GetMergedResources(IElementDefinition element)
Element.SetParent(Element value)
Element.OnChildAdded(Element child)
Element.AddLogicalChild(Element element)
Application.AddWindow(Window window)
IApplication.CreateWindow(IActivationState activationState)
This error is a result of the following lines of code:
maui/src/Controls/src/Core/Application/Application.cs
Lines 42 to 49 in 210bc35
This isn't initially obvious as to either the problem or the solution as it requires implementing "Obsolete" code in order for a very basic scenario to work in a Unit Test.
Steps to Reproduce
var mauiBuilder = MauiApp.CreateBuilder()
.UseMauiApp<Application>();
mauiBuilder.Services.AddTransient<IWindowCreator, WindowCreator()
.AddTransient<TestPage>();
var mauiApp = mauiBuilder.Build();
var app = mauiApp.Services.GetRequiredService<IApplication>();
var activationState = new ActivationState(new MauiContext(mauiApp.Services));
var window = app.CreateWindow(activationState);
private record WindowCreator(TestPage Page) : IWindowCreator
{
public Window CreateWindow(Application app, IActivationState? activationState) => new Window(Page);
}
public class TestPage : ContentPage
{
public TestPage()
{
Title = nameof(TestPage);
Content = new Label { Text = "Unit Tests" };
}
}
Link to public reproduction project repository
No response
Version with bug
8.0.80 SR8
Is this a regression from previous behavior?
Yes, this used to work in Xamarin.Forms
Last version that worked well
Unknown/Other
Affected platforms
Other (Tizen, Linux, etc. not supported by Microsoft directly)
Affected platform versions
No response
Did you find any workaround?
While this technically does work... it shouldn't be something that is needed just to run Unit Tests.
#pragma warning disable CS0612 // Type or member is obsolete
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Internals;
using Prism.Ioc.Tests.Mocks;
[assembly: Dependency(typeof(MockResourcesProvider))]
[assembly: Dependency(typeof(MockFontNamedSizeService))]
namespace Prism.Ioc.Tests.Mocks;
[Obsolete]
internal class MockResourcesProvider : ISystemResourcesProvider
{
public IResourceDictionary GetSystemResources()
{
var dictionary = new ResourceDictionary();
Style style;
style = new Style(typeof(Label));
dictionary[Device.Styles.BodyStyleKey] = style;
style = new Style(typeof(Label));
style.Setters.Add(Label.FontSizeProperty, 50);
dictionary[Device.Styles.TitleStyleKey] = style;
style = new Style(typeof(Label));
style.Setters.Add(Label.FontSizeProperty, 40);
dictionary[Device.Styles.SubtitleStyleKey] = style;
style = new Style(typeof(Label));
style.Setters.Add(Label.FontSizeProperty, 30);
dictionary[Device.Styles.CaptionStyleKey] = style;
style = new Style(typeof(Label));
style.Setters.Add(Label.FontSizeProperty, 20);
dictionary[Device.Styles.ListItemTextStyleKey] = style;
style = new Style(typeof(Label));
style.Setters.Add(Label.FontSizeProperty, 10);
dictionary[Device.Styles.ListItemDetailTextStyleKey] = style;
return dictionary;
}
}
[Obsolete]
public class MockFontNamedSizeService : IFontNamedSizeService
{
public double GetNamedSize(NamedSize size, Type targetElement, bool useOldSizes)
{
return size switch
{
NamedSize.Default => 12,// new MockFontManager().DefaultFontSize,
NamedSize.Micro => (double)4,
NamedSize.Small => (double)8,
NamedSize.Medium => (double)12,
NamedSize.Large => (double)16,
_ => throw new ArgumentOutOfRangeException(nameof(size)),
};
}
}
#pragma warning restore CS0612 // Type or member is obsolete
Relevant log output
No response