android 上调用 xunit 测试
  1. 工具地址 https://github.com/mattleibow/DeviceRunners

  2. 工具功能

    1. 在 android 上提示一个界面,选择并执行测试函数并显示日志,
    2. 支持 ui 自动化测试
    3. 支持桌面端启动 android 自动化启动测试并接收测试结果
    4. 支持 windows / linux / macos / android / ios
  3. 没有找到提供的现成的工具及 nuget 包,手册中提供的 nuget 库中没有找到相应的 nuget 包. 需要自行编译

  4. 下载 DeviceRunners

    1. src 目录下为 DeviceRunners 的源代码
    2. test 目录下为测试 DeviceRunners 相关代码
    3. sample/src 目录下为演示而写的一个 maui 项目 (DeviceTestingKitApp)
    4. sample/test 测试 DeviceTestingKitApp 的项目, 为了演示如何使用 DeviceRunners
  5. 卸载 testsample 目录下的项目, 修改 src 下所有项目中的 <TargetFramework> 部分的内容, 只保存 net10.0 及 net10.0-android (原项目使用 .net 9, 我的项目使用的 .net 10 ), 因为我只用 android 与 公共库部分。 其它的都删除掉

  6. 编译项目,在项目目录下生成 artifacts\bin 目录,里面为需要的工具

  7. 新建测试项目, 必须选择 maui 项目,

    1. 可以参见 DeviceRunners 中的示例项目 DeviceTestingKitApp.DeviceTests 进行修改
    2. 项目配置文件中保存 <TargetFramework>net10.0-android</TargetFramework> , 其它 TargetFramework 项目删除
    3. 根据需要修改项目配置中的 ApplicationId, 比如 com.example.devicetestingkitapp.test
    4. 修改 MainActivity.cs 中加入 name$(ApplicationId).MainActivity , 比如 com.example.devicetestingkitapp.test
    5. 添加 nugetxunitxunit.runner.utility
    6. 需要日志的话可以添加 Microsoft.Extensions.Logging.Console|Debug
    7. 添加 DeviceRunners 中生成的 DeviceRunners.UITesting.Maui.dll, DeviceRunners.VisualRunners.dll, DeviceRunners.VisualRunners.Maui.dll, DeviceRunners.VisualRunners.Xunit.dll
    8. 添加编译开关 <DefineConstants Condition="'$(TestingMode)' == 'NonInteractiveVisual'">$(DefineConstants);MODE_NON_INTERACTIVE_VISUAL</DefineConstants>
  8. 修改 MauiProgram.cs 代码

    指定扫描哪个程序集中的测试类
    指定是否启用自动工作模式

public static MauiApp CreateMauiApp() {
  var builder = MauiApp.CreateBuilder();
  builder
    .ConfigureUITesting()
  #if MODE_XHARNESS // 这里支持 XHARNESS 工具测试
    .UseXHarnessTestRunner(conf => conf
      .AddTestAssembly(typeof (MauiProgram).Assembly)
      .AddTestAssemblies(typeof (DeviceTestingKitApp.MauiLibrary.XunitTests.UnitTests).Assembly)
      .AddXunit())
  #endif
    .UseVisualTestRunner(conf => conf 
#if MODE_NON_INTERACTIVE_VISUAL # 这里自动启动测试,并通过 16384 端口传输结果给 pc 端
      .EnableAutoStart(true)
      .AddTcpResultChannel(new TcpResultChannelOptions {
        HostNames = ["localhost", "10.0.2.2"],
          Port = 16384,
          Formatter = new TextResultChannelFormatter(),
          Required = false,
          Retries = 3,
          RetryTimeout = TimeSpan.FromSeconds(5),
          Timeout = TimeSpan.FromSeconds(30)
      }) #endif
      .AddConsoleResultChannel()
      .AddTestAssembly(typeof (MauiProgram).Assembly) // 测试代码所在 assembly
      .AddTestAssemblies(typeof(MainTest).Assembly)
      .AddXunit());

  #if DEBUG
  builder.Logging.AddDebug();
  #else
  builder.Logging.AddConsole();
  #endif

  return builder.Build();
}
  1. 启动程序,在手机中可以看到测试界面,根据需要点击函数对应的按钮进行测试

  2. 如果编译时指定。NonInteractiveVisual 模式, 则会自动启动测试,并返回测试结果给 pc 端, pc 端使用工具可以接收测试结果并保存至本地 ( logcat.txt, tcp-test-results.txt )

    1. 编译时指定 -p:TestingMode=NonInteractiveVisual 参数
    2. 使用运行工具 DeviceRunners.Cli android test $apkFile --results-directory ./bin/test-results,
    3. 注 1:手册中工具为 device-runners 实际编辑时出的工具为 DeviceRunners.Cli
    4. 注 2:需要 adb reverse tcp:16384 tcp:16384 将端口映射出来, 手册中好像没有说明
  3. 一个工作脚本


$ErrorActionPreference = "Stop"

$currentDir = $PSScriptRoot
Set-Location $currentDir
[System.IO.Directory]::SetCurrentDirectory($currentDir)

echo "当前目录: $currentDir"

$outputDir = Join-Path $currentDir -ChildPath 'bin/publish_output'
echo "输出目录: $outputDir"

echo "移除 obj 目录"
$objDir = Join-Path $currentDir -ChildPath 'obj'
Remove-Item -Path $objDir  -Recurse -Force -ErrorAction SilentlyContinue

echo "发布项目" 
# TestingMode=NonInteractiveVisual, 项目配置中指定该参数后,启用宏定义 NonInteractiveVisual, apk 启用后自动运行单元测试并通过约定端口传出
# 如果不用 NonInteractiveVisual 参数,则 $toolApp android uninstall ,然后 $toolApp android launch 就可以了
dotnet publish . -c Release -r 'android-arm64' -f net10.0-android -p:TestingMode=NonInteractiveVisual  -o $outputDir
if (-not $?)
{
    throw "dotnet publish failed"
}

# 获取生成的 apk 应用
$apkfile = Get-ChildItem $outputDir -Filter '*-Signed.apk' | Select-Object -First 1 | % FullName
if (-not $apkfile)
{
    throw "no apk file found"
}

$apkfile = Resolve-Path $apkfile
echo "apk file: $apkfile"

# 这里是我编译的 DeviceRunners.Cli 
$toolApp = Join-Path $currentDir -ChildPath '../Tools/DeviceRunners.Cli/DeviceRunners.Cli'
if (-not (Test-Path $toolApp))
{
    throw "no tool app found"
}

$toolApp = Resolve-Path $toolApp
echo "tool app: $toolApp"

echo '删除旧的测试应用'
& $toolApp android uninstall --package com.iox.kebooapp.android.test
if (-not $?)
{
    echo 'uninstall failed'
}

echo '创建手机通讯隧道'
adb reverse tcp:16384 tcp:16384
if (-not $?)
{
    echo 'adb reverse failed'
}

echo '安装并自动测试应用'
& $toolApp android test --app $apkfile  --results-directory ./bin/test-results
上一篇
下一篇