Giter Club home page Giter Club logo

uno.ui.runtimetests.engine's Introduction

Uno.UI Runtime Tests Engine

Uno.UI Provides a in-app test runner for applications wanting to run unit tests in their target environment.

This engine uses the MSTest attributes to perform the discovery of tests.

Supported features

  • Running on or off the UI Thread
  • Using Data Rows
  • Running tests full screen
  • Generating an nunit report for CI publishing

Structure of the package

This package is built as a source package. It includes XAML files and cs files into the referencing project, making it independent from the Uno.UI version used by your project. It is built in such a way that Uno.UI itself can use this package while not referencing itself through nuget packages dependencies.

Using the Runtime Tests Engine

  • Add the Uno.UI.RuntimeTests.Engine nuget package to the head projects.
  • Add the following xaml to a page in your application:
    <Page xmlns:runtimetests="using:Uno.UI.RuntimeTests" ...>
        <runtimetests:UnitTestsControl />
    </Page>
  • For unoapp (WinUI) solution only, add the following to the Windows head project:
    <PropertyGroup>
        <DefineConstants>$(DefineConstants);WINDOWS_WINUI</DefineConstants>
    </PropertyGroup>
    note: This should not be added to the Windows head project of an unoapp-uwp (UWP) solution.

The test control will appear on that page.

Write your tests as follows:

[TestClass]
public class Given_MyClass
{
    [TestMethod]
    public async Task When_Condition()
    {
        // Use MSTests asserts or any other assertion frameworks
    }
}

Interacting with content in a test

The right side of the Runtime Tests control can display actual controls created by tests.

To set content here, use the UnitTestsUIContentHelper.Content property:

[TestClass]
public class Given_MyClass
{
    [TestMethod]
    public async Task When_Condition()
    {
        var SUT  = new TextBlock(); 
        UnitTestsUIContentHelper.Content = SUT;
        
        await UnitTestsUIContentHelper.WaitForIdle();
        // or await UnitTestsUIContentHelper.WaitForLoaded(SUT);
		
        // Use MSTests asserts or any other assertion frameworks
    }
}

Using UnitTestsUIContentHelper in a separate assembly

If you want to use the UnitTestsUIContentHelper in a separate assembly, you will need to add the following clas to the separate project:

public static class UnitTestsUIContentHelperProxy
{
	public static Action<UIElement?>? ContentSetter { get; set; }
	public static Func<UIElement?>? ContentGetter { get; set; }

	public static UIElement? Content 
    { 
        get => ContentGetter?.Invoke();
        set => ContentSetter?.Invoke(value);
    }
}

Then in the page that defines the UnitTestsControl, add the following:

public MyPage()
{
    InitializeComponent();

	// Initialize the UnitTestsUIContentHelperProxy for the test assembly
    UnitTestsUIContentHelperProxy.ContentSetter = e => UnitTestsUIContentHelper.Content = e;
	UnitTestsUIContentHelperProxy.ContentGetter = () => UnitTestsUIContentHelper.Content;
}

Attributes for handling UI specific behavior

The behavior of the test engine regarding tests can be altered using attributes.

RequiresFullWindowAttribute

Placing this attribute on a test will switch the rendering of the test render zone to be full screen, allowing for certain kind of tests to be executed.

RunsOnUIThreadAttribute

Placing this attribute on a test or test class will force the tests to run on the dispatcher. By default, tests run off of the dispatcher.

InjectedPointerAttribute

This attribute configures the type of the pointer that is simulated when using helpers like App.TapCoordinates(). You can define the attribute more than once, the test will then be run for each configured type. When not defined, the test engine will use the common pointer type of the platform (touch for mobile OS like iOS and Android, mouse for browsers, skia and other desktop platforms).

Placing tests in a separate assembly

  • In your separated test assembly

    • Add a reference to the "Uno.UI.RuntimeTests.Engine" package
    • Then define the following in your csproj:
       <PropertyGroup>
       	<DefineConstants>$(DefineConstants);UNO_RUNTIMETESTS_DISABLE_UI</DefineConstants>
       </PropertyGroup>
  • In your test application

    • Add a reference to the "Uno.UI.RuntimeTests.Engine" package
    • Then define the following in your csproj:
       <PropertyGroup>
       	<DefineConstants>$(DefineConstants);UNO_RUNTIMETESTS_DISABLE_LIBRARY</DefineConstants>
       </PropertyGroup>

Alternative method

Alternatively, if you have only limited needs, in your separated test assembly, add the following attributes code:

using System;
using Windows.Devices.Input;

namespace Uno.UI.RuntimeTests;

public sealed class RequiresFullWindowAttribute : Attribute { }

public sealed class RunsOnUIThreadAttribute : Attribute { }

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class InjectedPointerAttribute : Attribute
{
    public PointerDeviceType Type { get; }

    public InjectedPointerAttribute(PointerDeviceType type)
    {
        Type = type;
    }
}

and define the following in your csproj:

 <PropertyGroup>
  <DefineConstants>$(DefineConstants);UNO_RUNTIMETESTS_DISABLE_UI</DefineConstants>
     <DefineConstants>$(DefineConstants);UNO_RUNTIMETESTS_DISABLE_INJECTEDPOINTERATTRIBUTE</DefineConstants>
     <DefineConstants>$(DefineConstants);UNO_RUNTIMETESTS_DISABLE_REQUIRESFULLWINDOWATTRIBUTE</DefineConstants>
     <DefineConstants>$(DefineConstants);UNO_RUNTIMETESTS_DISABLE_RUNSONUITHREADATTRIBUTE</DefineConstants>
 </PropertyGroup>

These attributes will ask for the runtime test engine to replace the ones defined by the Uno.UI.RuntimeTests.Engine package.

Running the tests automatically during CI

When your application references the runtime-test engine, as soon as you start it with the following environment variables, the runtime-test engine will automatically run the tests on application startup and then kill the app.

  • UNO_RUNTIME_TESTS_RUN_TESTS: This can be either
    • A json serialized test configuration (use {} to run with default configuration);
    • A filter string.
  • UNO_RUNTIME_TESTS_OUTPUT_PATH: This is the output path of the test result file

You can also define some other configuration variables:

  • UNO_RUNTIME_TESTS_OUTPUT_KIND: Selects the kind of the test result file, possible values are NUnit (default) or UnoRuntimeTests (cf. TestResultKind)

Currently, the easiest way to run runtime-tests on the CI is using the Skia-GTK head. Here is an example of an Azure pipeline configuration file:

jobs:
- job: Skia_Tests
  displayName: 'Runtime Tests - Skia GTK'
  timeoutInMinutes: 60
  
  pool:
    vmImage: 'ubuntu-20.04'

  variables:
    NUGET_PACKAGES: $(build.sourcesdirectory)/.nuget

  steps:
  - checkout: self
    clean: true
    
  - task: UseDotNet@2
    displayName: 'Use .NET'
    inputs:
      packageType: 'sdk'
      version: '7.x'
      
  - script: |
        dotnet tool install -g uno.check
        uno-check --target skiagtk --fix --non-interactive --ci
    
    displayName: 'Run uno-check'    

  - script: dotnet build Uno.Extensions.RuntimeTests.Skia.Gtk.csproj -c Release -p:UnoTargetFrameworkOverride=net7.0 -p:GeneratePackageOnBuild=false -bl:$(Build.ArtifactStagingDirectory)/skia-gtk-runtime-test-build.binlog
    displayName: 'Build Runtime Tests app (GTK)'
    workingDirectory: $(Build.SourcesDirectory)/src/Uno.Extensions.RuntimeTests/Uno.Extensions.RuntimeTests.Skia.Gtk

  - task: PublishBuildArtifacts@1
    displayName: Publish Build Logs
    retryCountOnTaskFailure: 3
    condition: always()
    inputs:
      PathtoPublish: $(build.artifactstagingdirectory)/skia-gtk-runtime-test-build.binlog
      ArtifactName: skia-runtime-test-build
      ArtifactType: Container

  - script: xvfb-run --auto-servernum --server-args='-screen 0 1280x1024x24' dotnet Uno.Extensions.RuntimeTests.Skia.Gtk.dll
    displayName: 'Run Runtime Tests (GTK)'
    workingDirectory: $(Build.SourcesDirectory)/src/Uno.Extensions.RuntimeTests/Uno.Extensions.RuntimeTests.Skia.Gtk/bin/Debug/net7.0
    env:
      UNO_RUNTIME_TESTS_RUN_TESTS: '{}'
      UNO_RUNTIME_TESTS_OUTPUT_PATH: '$(Common.TestResultsDirectory)/skia-gtk-runtime-tests-results.xml'

  - task: PublishTestResults@2
    displayName: 'Publish GTK Runtime Tests Results'
    condition: always()
    retryCountOnTaskFailure: 3
    inputs:
      testRunTitle: 'GTK Runtime Tests Run'
      testResultsFormat: 'NUnit'
      testResultsFiles: '$(Common.TestResultsDirectory)/skia-gtk-runtime-tests-results.xml'
      failTaskOnFailedTests: true 

Notes:

  • This is running the GTK head using a virtual x-server (xvfb).
  • We use {} for the UNO_RUNTIME_TESTS_RUN_TESTS in order to run all tests with default configuration.
  • If you want to test hot-reload scenarios (usually relevant only for library developers), you need to build your test project in debug (-c Debug).

Running the tests automatically during CI on WASM and mobile targets

Alternatively, you can also run the runtime-tests on the CI using "UI Tests". Here is an example of how it's integrated in uno's core CI](https://github.com/unoplatform/uno/blob/master/src/SamplesApp/SamplesApp.UITests/RuntimeTests.cs#L32.

uno.ui.runtimetests.engine's People

Contributors

agneszitte avatar dr1rrb avatar jeromelaban avatar kazo0 avatar xiaoy312 avatar youssef1313 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uno.ui.runtimetests.engine's Issues

QoL: Add additional info/context for test failure message

What would you like to be added:

Some way to writing to a string buffer that will be included when the test fail. This message should be included in the ci error report and in the output area of the test runner.

Why is this needed:

This could be used to add additional info/context for debugging. Also, it is annoying to add message with full context to every assert method.

For which Platform: All of them

Anything else we need to know?

Sort of what is done in unoplatform/uno#2804, but from the test impl side.
SO answer says that we could use Trace.WriteLine(). To validate if this will appear on ci. If so, we could add listener to it to pipe to the test runner's output area.

Add ImageAssert Helpers

Migrate assertion helpers from Uno's runtime tests such as the ImageAssert

Not sure if we'd want to create a separate Helpers package like we do for Uno.UITest or it'd just be simpler to include within the main runtime test engine package.

Create library instead of pushing code to the using app

What would you like to be added:

Create library instead of pushing code to the using app

Why is this needed:

#119

For which Platform:

  • iOS
  • Android
  • WebAssembly
  • WebAssembly renders for Xamarin.Forms
  • Windows
  • Build tasks

Anything else we need to know?

Need to consider the special case of Uno

Cleanup after a runtime test should close all `Popups` and clear `Content`

Current behavior

If a test uses Content or opens Popups, they will stay open between tests unless explicitly cleaned up within the test.

Expected behavior

Should be avoided for clean start of tests.

How to reproduce it (as minimally and precisely as possible)

No response

Workaround

No response

Works on UWP/WinUI

No response

Environment

No response

NuGet package version(s)

No response

Affected platforms

No response

IDE

No response

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

No response

included test app crashes on windows.

Current behavior

src/Uno.UI.RuntimeTests.Engine/Uno.UI.RuntimeTests.Engine.Windows/Uno.UI.RuntimeTests.Engine.Windows.csproj
throws an exception on launch:

System.DllNotFoundException: 'Unable to load DLL 'Microsoft.ui.xaml.dll' or one of its dependencies: The specified module could not be found. (0x8007007E)'
	at Uno.UI.RuntimeTests.Engine.Windows.dll!Uno.UI.RuntimeTests.Engine.Program.Main(string[] args = {string[0]}) Line 28	C#

Expected behavior

^ should not crash

Anything else we need to know?

Under the winui "PROJECT_NAME.Windows" head directory, there is a folder named "Properties" which is missing in this repo, and .gitignore-ed.
It is normally present when you create a new project. If you add it back, the app will launch without exception.

said folder: https://github.com/unoplatform/uno/tree/4.6.19/src/SolutionTemplate/UnoSolutionTemplate.WinUI.netcore/WinUI/Properties

Tests are run twice.

when using a separate assembly for tests and said assembly name ends with "tests",
the tests are run twice.

var testAssembliesTypes =
	from asm in AppDomain.CurrentDomain.GetAssemblies()
	where asm.GetName()?.Name?.EndsWith("tests", StringComparison.OrdinalIgnoreCase) ?? false
	from type in asm.GetTypes()
	select type;

var types = GetType().GetTypeInfo().Assembly.GetTypes().Concat(testAssembliesTypes);

^ AppDomain.CurrentDomain.GetAssemblies() definitely contains GetType().GetTypeInfo().Assembly.GetTypes()

Respect `[Timeout]`

What would you like to be added:

Currently the [Timeout] attribute for test methods does not seem to be respected.

Why is this needed:

Specify custom timeout for specific tests.

For which Platform:

All

0.24.0-dev.95 only works with release builds

Current behavior

For a solution using 0.24.0-dev.95 Any test project that references another project, it looks for a NuGet package source in a path relative to the referenced project and in a \Release directory.

Expected behavior

It should not do anything dependeny on the type of build.
I should be able to build test projects and execute tests in debug mode without first having to do a local release build!

How to reproduce it (as minimally and precisely as possible)

  • Create a test project using v0.24.0-dev.95 of the library
  • Reference another project in the solution.
  • Make sure in DEBUG mode
  • Try and build the test project (or the whole solution)
  • Get an exception like Error NU1301 The local source 'C:\[PATH TO REFERENCED PROJECT]\Release' doesn't exist.

Internal Uno project available for repro/test if needed.

Environment

Nuget Package:

Uno.UI.RuntimeTests.Engine

Package Version(s):

0.24.0-dev.95

Affected platform(s):

  • Testing
  • iOS
  • Android
  • WebAssembly
  • WebAssembly renders for Xamarin.Forms
  • Windows
  • Build tasks

Visual Studio:

  • 2022 (17.9.0 Preview 1)

  • 2017 (version: )

  • 2019 (version: )

  • for Mac (version: )

Relevant plugins:

  • Resharper (version: )

Anything else we need to know?

Did this happen because any CI checks run as Release but developers often work in Debug mode and build and run tests in this mode?

Add ability to test hot-relaod scenario

What would you like to be added:

Ability to test hot-relaod scenario

For which Platform:

  • iOS
  • Android
  • WebAssembly
  • WebAssembly renders for Xamarin.Forms
  • Windows
  • Build tasks
  • Skia

QoL: improve search filter

What would you like to be added:

  • filter tests by both class name and method name.
  • match by both class and method: listview measure
  • negative filter: listview measure -recycle

pseudo code:

isMatch = term.Split(' ')
	.All(x => (test.ClassName+'.'+test.Name).Contains(x.TrimStart('-'), ignoreCase: true) != x.StartWith('-'))

Why is this needed:

Typing is hard, especially on device with some form of input lag, auto-correkt and limited screen space (see: #30).
Some test name is also a subset of another, and is impossible to single it out.

For which Platform: All of them.

Anything else we need to know?

Often I would suffix _Asd to the tests of interest, and forget to remove them in the actual PR.

Add ImageAssert Helpers

Migrate assertion helpers from Uno's runtime tests such as the ImageAssert

Not sure if we'd want to create a separate Helpers package like we do for Uno.UITest or it'd just be simpler to include within the main runtime test engine package.

netstandard2.0 project refencing this package fails to build: No overload for method 'Contains' takes 2 arguments

Current behavior

3>C:\Users\Xiaoy312\.nuget\packages\uno.ui.runtimetests.engine\0.1.0-dev.32\src\UnitTestsControl.cs(678,85,678,94): error CS1501: No overload for method 'Contains' takes 2 arguments
3>C:\Users\Xiaoy312\.nuget\packages\uno.ui.runtimetests.engine\0.1.0-dev.32\src\UnitTestsControl.cs(682,53,682,62): error CS1501: No overload for method 'Contains' takes 2 arguments
3>C:\Users\Xiaoy312\.nuget\packages\uno.ui.runtimetests.engine\0.1.0-dev.32\src\UnitTestsControl.cs(683,34,683,42): error CS1501: No overload for method 'Contains' takes 2 arguments

Expected behavior

^ should not fail.

How to reproduce it (as minimally and precisely as possible)

reference this package, and target netstandard2.0

Environment

Nuget Package: Uno.UI.RuntimeTests.Engine
Package Version(s): [email protected]
Affected platform(s): netstandard2.0

Anything else we need to know?

https://stackoverflow.com/questions/63371180/replacement-for-string-containsstring-stringcomparison-in-net-standard-2-0

CS0152: The switch statement contains multiple cases with the label value '"Uno.UI.RuntimeTests.UnitTestsControl"'

Current behavior

6>D:\code\uno\platform\Uno.Toolkit\samples\Uno.Toolkit.WinUI.Samples\Uno.Toolkit.WinUI.Samples.Droid\Uno.UI.SourceGenerators\Uno.UI.SourceGenerators.BindableTypeProviders.BindableTypeProvidersSourceGenerator\BindableMetadata.g.cs(35062,5,35062,49): 
error CS0152: The switch statement contains multiple cases with the label value '"Uno.UI.RuntimeTests.UnitTestsControl"'

How to reproduce it (as minimally and precisely as possible)

  • separate assembly references Uno.UI.RuntimeTests.Engine
  • project heads references Uno.UI.RuntimeTests.Engine and the separate assembly
    ^ roject heads: PROJECT_NAME.iOS.csproj, PROJECT_NAME.Wasm.csproj, etc.

Expand Test Pane on Mobile

Current behavior

When running on a mobile platform such as Android the Test Pane is half the screen width which makes the filter Text Block and Run Tests button unusable.

Expected behavior

This should take the full screen width

How to reproduce it (as minimally and precisely as possible)

Environment

Nuget Package: Uno.UI.RuntimeTests.Engine

Package Version(s): 0.1.0-dev.27

Affected platform(s):

  • iOS
  • Android
  • WebAssembly
  • WebAssembly renders for Xamarin.Forms
  • Windows
  • Build tasks

Visual Studio:

  • 2017 (version: )
  • 2019 (version: )
  • for Mac (version: )

Relevant plugins:

  • Resharper (version: )

Anything else we need to know?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.