Saucery.TUnit
0.7.19
Prefix Reserved
dotnet add package Saucery.TUnit --version 0.7.19
NuGet\Install-Package Saucery.TUnit -Version 0.7.19
<PackageReference Include="Saucery.TUnit" Version="0.7.19" />
paket add Saucery.TUnit --version 0.7.19
#r "nuget: Saucery.TUnit, 0.7.19"
// Install Saucery.TUnit as a Cake Addin #addin nuget:?package=Saucery.TUnit&version=0.7.19 // Install Saucery.TUnit as a Cake Tool #tool nuget:?package=Saucery.TUnit&version=0.7.19
Saucery.TUnit
Saucery handles all the plumbing required to integrate with SauceLabs, making writing TUnit tests a breeze, so you only need to tell Saucery what you want. Saucery takes care of the how.
Note: The tests specified below are provided as examples only. Your tests, of course, will be specific to your System Under Test.
Initial Setup
- You'll need a SauceLabs account. You can get a free trial account here.
- If you want to run your tests locally you need to set 2 environment variables, SAUCE_USER_NAME and SAUCE_API_KEY
- To run your test suite from your GitHub Actions pipeline you need to set two secrets SAUCE_USER_NAME and SAUCE_API_KEY. Instructions on how to set Github Secrets are here.
Writing TUnit Tests
- In your solution create a simple class library.
- Add a NuGet Reference to Saucery.TUnit.
Your Project file should look something like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Saucery.TUnit" Version="0.6.0" />
</ItemGroup>
</Project>
IDE Setup
Follow the instructions here to set up your IDE.
The ExternalMerlin.TUnit dogfood integration tests use the following template:
using ExternalMerlin.XUnit.PageObjects;
using Saucery.Core.Dojo;
using Saucery.TUnit;
namespace Merlin.TUnit.RealDevices;
public class DataDrivenTests : SauceryTBase
{
[Test]
[MethodDataSource(nameof(AllCombinations), Arguments = [new[] { 4, 5 }])]
public async Task DataDrivenTest(BrowserVersion requestedPlatform, int data)
{
InitialiseDriver(requestedPlatform);
var guineaPigPage = new GuineaPigPage(SauceryDriver(), "https://saucelabs.com/");
guineaPigPage.TypeField(SauceryDriver(), "comments", data.ToString());
var commentField = guineaPigPage.GetField(SauceryDriver(), "comments");
await Assert.That(commentField).IsNotNull();
var commentText = commentField.GetDomProperty("value");
await Assert.That(commentText).Contains(data.ToString());
}
public static IEnumerable<Func<(BrowserVersion, int)>> AllCombinations(int[] data) =>
RequestedPlatformData
.AllPlatforms()
.SelectMany(
browserVersionFunc => data,
(browserVersionFunc, datum) => new Func<(BrowserVersion, int)>(() => (browserVersionFunc(), datum))
);
}
The above code will run 2 unit tests (2 DataDrivenTitle tests) on all the platforms you specify, in parallel by default.
Parallelism
- Parallelism in TUnit is default out of the box. For SauceLabs it needs to be constrained.
- Have a look at MyParallelLimit.cs in the ExternalMerlin.TUnit project for an example of how to do that.
- We recommend 2 less than your limit. Our OpenSauce account has 5 so we specify 3 in our internal testing.
The other lines are mandatory. Let's break the key lines down.
public class DataDrivenTests : SauceryTBase
Your class must subclass SauceryTBase
. SauceryT will take care of the rest.
A data driven test is specified like this:
[Test]
[MethodDataSource(nameof(AllCombinations), Arguments = [new[] { 4, 5 }])]
public async Task DataDrivenTest(Func<BrowserVersion> requestedPlatform, int data)
You can call the class what you like but it must take a Func<BrowserVersion>
and the data
as a parameter and subclass SauceryTBase
.
[MethodDataSource(nameof(AllCombinations)...]
is how you tell SauceryT what platforms you want to test on. You need to specify a class to do that. In this example its called RequestedPlatformData
but you can call it anything you like.
Let's look at what it should contain.
using Saucery.Core.DataSources;
using Saucery.Core.Dojo;
using Saucery.Core.OnDemand;
using Saucery.Core.OnDemand.Base;
using Saucery.Core.Util;
namespace ExternalMerlin.TUnit;
public class RequestedPlatformData : SauceryTestData
{
static RequestedPlatformData()
{
var platforms = new List<SaucePlatform>
{
//Emulated Mobile Platforms
new AndroidPlatform("Google Pixel 8 Pro GoogleAPI Emulator", "15.0", SauceryConstants.DEVICE_ORIENTATION_PORTRAIT),
new IOSPlatform("iPhone 14 Pro Max Simulator", "16.2", SauceryConstants.DEVICE_ORIENTATION_LANDSCAPE),
//Desktop Platforms
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_11, SauceryConstants.BROWSER_CHROME, "123"),
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_10, SauceryConstants.BROWSER_CHROME, "124", SauceryConstants.SCREENRES_2560_1600)
};
SetPlatforms(platforms, PlatformFilter.Emulated);
}
public static List<Func<BrowserVersion>> AllPlatforms() => GetAllPlatformsAsFunc();
The List<SaucePlatform>
is what you will specify. The rest of the class is mandatory. Check out SauceryConstants
for all the platform, browser and screenres enums.
Platform Range Expansion
Platform range expansion is a feature unique to Saucery. Say you wanted to test on a range of browser versions but you didn't want to specify each individually. That's fine. Saucery supports specifying ranges.
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_11, SauceryConstants.BROWSER_CHROME, "100->119")
This will test on Windows 11 Chrome all available versions from 100 to 119 inclusive.
Real Devices
Yes, Saucery supports Real Devices!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net9.0
- Saucery.Core (>= 4.5.14)
- TUnit (>= 0.7.19)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.7.19 | 46 | 1/27/2025 |
0.7.9 | 227 | 1/25/2025 |
0.7.3 | 52 | 1/24/2025 |
0.7.0 | 71 | 1/23/2025 |
0.6.159 | 78 | 1/21/2025 |
0.6.154 | 153 | 1/21/2025 |
0.6.151 | 144 | 1/19/2025 |
0.6.145 | 58 | 1/19/2025 |
0.6.137 | 119 | 1/19/2025 |
0.6.123 | 159 | 1/18/2025 |
0.6.117 | 175 | 1/17/2025 |
0.6.100 | 109 | 1/14/2025 |
0.6.89 | 125 | 1/12/2025 |
0.6.81 | 117 | 1/11/2025 |
0.6.43 | 130 | 1/9/2025 |
0.6.33 | 133 | 1/5/2025 |
0.6.15 | 160 | 1/2/2025 |
0.6.0 | 258 | 12/28/2024 |
0.5.22 | 197 | 12/21/2024 |
0.5.6 | 246 | 12/18/2024 |
ChangeLog:
v4.0.0
- Initial Release with dependency on Saucery.Core