Posted on 26. May 2021

Модульные тесты WinUI для настольных ПК

Read this article in your language IT | EN | DE | ES

Юнит тесты

С самого начала универсальная платформа Windows поддерживала модульное тестирование с помощью нескольких платформ тестирования. Теперь, когда WinUI Desktop стал общедоступным и с учетом того, что вы не можете проводить разработку через тестирование без тестовой среды, потребовался новый способ создания тестов для него.

В этом сообщении блога мы сразу перейдем к тому, как создать проект модульного теста для WinUI Desktop с помощью MSTest!

MSTest

Я не буду вдаваться в подробности того, зачем вам нужны тесты в вашем проекте, так как есть много статей о том, почему модульное тестирование - хорошая идея, но быстрое повторение, в контексте контекста, всегда полезно.

MSTest - это платформа тестирования Microsoft, позволяющая разработчикам создавать тесты, полностью интегрированные с Visual Studio.  MSTest v2 - это полностью поддерживаемая кроссплатформенная реализация MSTest с открытым исходным кодом, которая поддерживает .Net Framework, .Net Core / .NET 5, ASP.Net, UWP, а теперь и WinUI.

Поскольку настольные приложения WinUI выполняются как упакованные в MSIX приложения .NET 5 (подробнее здесь), создание тестов для него очень похоже на создание тестов для .NET 5. Самое большое различие такое же, как и для приложений UWP: UI поток.

Учитывая, что WinUI Desktop еще совсем недавно, еще нет шаблонов в Project Reunion для создания модульных тестов на основе WinUI3, поэтому я проведу вас через шаги, необходимые для создания проекта модульного теста на основе приложения WinUI Desktop. Этот процесс аналогичен выполнению модульных тестов для приложений UWP.

Файл, Новый, Проект

После установки Project Reunion 0.5.7 VSIX можно создать новое упакованное пустое приложение WinUI Desktop:

Название проекта WinUIDesktopUnitTestApp1.

Удалите StackPanel и его содержимое из файла MainWindow.xaml и замените его пустым фреймом:

<Window

    x:Class="WinUIDesktopUnitTestApp1.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:local="using:WinUIDesktopUnitTestApp1"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d">

 

    <Frame />

</Window>

 

Обязательно удалите myButton_Click из файла MainWindow.xaml.cs. Оба эти шага просто очищают шаблон по умолчанию, поскольку это не нужно в модульных тестах.

А теперь самое интересное!

 

Предварительный просмотр возможностей!

Чтобы использовать модульные тесты в WinUI Desktop, нам необходимо включить предварительную версию MSIX, которая включается свойством EnablePreviewMsixTooling MSBuild. Он перейдет от двух проектов (csproj+ wapproj) к одному проекту (один csproj). В настоящее время эта функция все еще находится на стадии предварительного просмотра, поэтому нет шаблона, который помог бы ее использовать. Тем не менее, миграция существующего проекта для его использования не должна быть сложной задачей. Пройдем по шагам.

Во-первых, давайте вручную отредактируем WinUIDesktopUnitTestApp1.csproj, дважды щелкнув его в обозревателе решений. Внутри первого раздела PropertyGroup добавьте следующее:

 

<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
 
Также нужно переместить несколько файлов. Скопируйте папку Images, а также файл Package.appxmanifest из папки, в которой находится wapproj, в папку csproj. Я рекомендую вам сделать это через проводник, чтобы VS не пытался изменить ваш файл csproj. Теперь убедитесь, что ваш csproj ссылается на скопированные файлы, например: 
 
<ItemGroup>
    <AppxManifest Include="Package.appxmanifest">
        <SubType>Designer</SubType>
    </AppxManifest>
</ItemGroup>
<ItemGroup>
    <Content Include="Images\LockScreenLogo.scale-200.png" />
    <Content Include="Images\SplashScreen.scale-200.png" />
    <Content Include="Images\Square150x150Logo.scale-200.png" />
    <Content Include="Images\Square44x44Logo.scale-200.png" />
    <Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
    <Content Include="Images\StoreLogo.png" />
    <Content Include="Images\Wide310x150Logo.scale-200.png" />
</ItemGroup>
 
Теперь вы можете полностью удалить папкуwapproj (WinUIDesktopUnitTestApp1 (Package)), а также удалить ее из своего решения. Это все, что нужно для использования предварительной версии MSIX Tooling. У вас должно быть гораздо более чистое решение с одним проектом, подобным этому: 
 
Если вы создадите и запустите это приложение как есть, оно должно работать, но вы все равно не сможете создавать тесты. Теперь обновим этот проект, чтобы сделать его настоящим тестовым проектом. Сначала добавьте эту ItemGroup в свой csproj: 
<ItemGroup>
    <ProjectCapability Include="TestContainer" />
</ItemGroup>
 
Это помогает VS понять, что этот проект является тестовым. Вы можете заметить, что значок проекта в обозревателе решений изменится при сохранении csproj:
Также нужны новые пакеты NuGet, только что появившиеся! 
 
<ItemGroup>
    <PackageReference Include="MSTest.TestAdapter">
        <Version>2.2.4</Version>
    </PackageReference>
    <PackageReference Include="MSTest.TestFramework">
        <Version>2.2.4</Version>
    </PackageReference>
    <PackageReference Include="Microsoft.TestPlatform.TestHost">
        <Version>16.10.0</Version>
        <ExcludeAssets>build</ExcludeAssets>
    </PackageReference>
</ItemGroup>
 
Обратите внимание на сборку <ExcludeAssets>build</ExcludeAssets> в узле Microsoft.TestPlatform.TestHost PackageReference.
 
 

Это позволит ссылаться на типы MSTest, а также правильно создавать и запускать тесты.

 

Теперь нужно активировать тестовое приложение, чтобы оно запускало необходимые тесты (по сравнению с простым запуском приложения и запуском всех тестов постоянно). Давайте отредактируем метод OnLaunched из файла App.xaml.cs:

 

using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
 
...
 
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
 
    m_window = new MainWindow();
 
    // Ensure the current window is active
    m_window.Activate();
 
    UITestMethodAttribute.DispatcherQueue = m_window.DispatcherQueue;
 
    // Replace back with e.Arguments when https://github.com/microsoft/microsoft-ui-xaml/issues/3368 is fixed
    Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(Environment.CommandLine);
}

 

Теперь единственная недостающая часть - это собственно тестовый файл с нашими тестами. Создайте новый файл C# с простым тестом внутри него:

using Microsoft.VisualStudio.TestTools.UnitTesting;
 
namespace WinUIDesktopUnitTestApp1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            Assert.AreEqual(0, 0);
        }
    }
}
 
Просто сохранив этот файл, вы увидите, что тесты правильно обнаруживаются в Test Explorer VS:

Щелкните правой кнопкой мыши тест и просто запустите его. Это построит проект, развернет ваш пакет MSIX, запустит ваши тесты и обновит Test Explorer с результатами!

 

Помните, что это все еще находится на стадии предварительного просмотра. Закрытие VS и его повторное открытие обычно помогает решить некоторые проблемы, так что имейте это в виду, если что-то кажется нестабильным.

 

Теперь, когда основы работают, давайте создадим тест, который использует атрибут Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer.UITestMethodAttribute. Это позволяет вам запускать код непосредственно в потоке пользовательского интерфейса вашего окна WinUI3. Весьма вероятно, что вам нужно будет это сделать, учитывая тот факт, что любой код, который создает или изменяет элемент пользовательского интерфейса, обычно должен выполняться из потока пользовательского интерфейса. Такой простой код, как var grid = new Grid(), вызовет исключение, если вы попытаетесь запустить его из обычного TestMethod:

 

TestMethod1
   Source: UnitTest1.cs line 11
   Duration: 44 ms
 
  Message: 
    Test method WinUIDesktopUnitTestApp1.UnitTest1.TestMethod1 threw exception: 
    System.Runtime.InteropServices.COMException: The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD)) For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread.
  Stack Trace: 
    ExceptionHelpers.ThrowExceptionForHR(Int32 hr)
    _IGridFactory.CreateInstance(Object baseInterface, IntPtr& innerInterface)
    Grid.ctor()
    UnitTest1.TestMethod1()

К счастью, совершенно ясно, что мы должны сделать, чтобы исправить проблему, поэтому просто замените [TestMethod] на [UITestMethod], добавив оператор используемый Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer, который заставит этот тест выполняться в потоке пользовательского интерфейса.

И вот оно:

 

Это всего лишь основы того, чего можно достичь с помощью простого теста, но более сложные сценарии тестирования могут быть реализованы на основе этого проекта.

Спасибо, что прочитали, и увидимся в следующий раз!

 

Источник



Comments are closed