13

I have a simple Window with a reference to a StaticResource in the App.xaml.

App.xaml resource definition:

<!-- Standard Text Box Style -->
<Style x:Key="textBoxStyleStd" TargetType="{x:Type TextBox}">
    <Setter Property="FontSize" Value="14" />
</Style>

Window componets using the resource:

<TextBlock Grid.Column="1" Grid.Row="0" Name="stationIdTitle"
           Style="{StaticResource textBlockStyleStd}"
           VerticalAlignment="Center" HorizontalAlignment="Center"
           Text="{LocText Key=Title, Dict={StaticResource Dictionary},
               Assembly={StaticResource Assembly}}"/>

When trying to unit test this Window I get the error:

System.Windows.Markup.XamlParseException: Cannot find resource named '{textBlockStyleStd}'. Resource names are case sensitive. Error at object 'stationIdTitle' in markup file 'Zpg;component/guicomponenets/screens/enterstationidscreen.xaml' Line 23 Position 71.

Is there any way around this? My unit test code is:

[Test]
public void TestEnterKeyPressedNoText()
{
    IPickingBusinessObject pickingBusinessObject = mock.StrictMock<IPickingBusinessObject>();

    EnterStationIdScreen objectUnderTest = new EnterStationIdScreen(pickingBusinessObject);

    Assert.AreEqual(Visibility.Visible, objectUnderTest.stationIdError.Visibility);

    Assert.AreEqual("werwe", "oksdf");

    Replay();

    objectUnderTest.EnterKeyPressed();

    Verify();
}
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
James
  • 3,597
  • 11
  • 47
  • 57

4 Answers4

14

Thanks Kent,

I looked at your suggestions and in most scenarios I agree models should be used and tested however, there is some code associated with the controls (e.g. TextBox visibility) I still wanted to test. To get round this you can create an instance of your Application (but not initialize it) and add the resources manually. This does lead to duplication in the App.xaml and the base unit test but this allows me to complete the tests I wanted.

        if (Application.Current == null)
        {
            App application = new App();

            #region Add Static Resources from the App.xaml

            Style textBoxStyle = new Style(typeof(TextBox));
            textBoxStyle.Setters.Add(new Setter(TextBox.FontSizeProperty, 14d));

            Style textBlockStyle = new Style(typeof(TextBlock));
            textBlockStyle.Setters.Add(new Setter(TextBlock.FontSizeProperty, 14d));

            application.Resources.Add("TextBoxStyleStd", textBoxStyle);
            application.Resources.Add("TextBlockStyleStd", textBlockStyle);
            application.Resources.Add("TextBlockStyleError", textBlockStyle);
            application.Resources.Add("Assembly", "Zpg");

            #endregion
        }       
MoMo
  • 8,149
  • 3
  • 35
  • 31
James
  • 3,597
  • 11
  • 47
  • 57
  • 5
    had a similar issue, just call app.InitializeComponent() next to creating the instance. the resource dictionaries will get populated. Infact thats what the Main method does. This is the snippet from the main method, you could skip the app.Run as we are unit testing here. [System.STAThreadAttribute()] [System.Diagnostics.DebuggerNonUserCodeAttribute()] public static void Main() { WPFComboBox.App app = new WPFComboBox.App(); app.InitializeComponent(); app.Run(); } – ioWint Aug 31 '11 at 23:53
  • 1
    Also, if you are using a static resource to base a `UserControl`'s `Style` on the default, such as ` – Jay Jun 19 '12 at 16:38
7

In the context of your unit test, there is no WPF application running. Therefore, the Window won't find the resource.

My way around this would be to not unit test your views. Instead, use MVVM and unit test your view models. If you want to test your views, write integration tests instead. Your integration tests can actually kick off the application and therefore much more closely imitate the real running of your app.

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
4

When I use fully qualified assembly names in my app.xaml resource entries, I only need to instanciate the App() class. In this example, all resources lies in the Majesty_of_Omega_GUI assembly, which is referred by the UnitTest.DLL

<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Majesty_of_Omega.GUI.App"
StartupUri="Pages/MainPage.xaml"
>
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/Majesty_of_Omega_GUI;component/Resources/MainScreens.xaml" />
            <ResourceDictionary Source="pack://application:,,,/Majesty_of_Omega_GUI;component/Resources/PanelResources.xaml" />
            <ResourceDictionary Source="pack://application:,,,/Majesty_of_Omega_GUI;component/Simple Styles.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>
</Application>

Test function:

    [Test]
    public void Testfunction()
    {
        if (Application.Current == null)
        {
            App application = new App();
        }

        SomePage page = new SomePage();
ChaosSpeeder
  • 3,468
  • 5
  • 30
  • 38
  • Hi ChaosSpeeder, i am trying the same but even then my application instance resources is not populated! – ioWint Aug 31 '11 at 20:46
  • ChaosSpeeder, I went with your approach and then found i neednt give the pack based URI! it worked even with out it. But i was forced to invoke app.InitializeComponent() to get the Resource dictionaries to get populated. – ioWint Aug 31 '11 at 23:52
  • This is a pretty old post, but I'm not having success with this approach using the pack based URI with or without the InitializeComponent() call. – Don Smith Dec 03 '14 at 00:55
  • It helps, it is worth to write that this notation (pack://application:,,,/....) is required in all nested files. – macieqqq Dec 20 '17 at 10:24
  • It worked for me, but I'm curious how the control can find the app instance we created within the method. – Hossein Ebrahimi Dec 05 '22 at 05:46
0

Actually, you can use the same Application and if the resources are from the same assembly, you've got to call the InitializeComponents methods to make it works (Source here).

Have a nice day !

Jonathan ANTOINE
  • 9,021
  • 1
  • 23
  • 33