Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sauceforge/saucery
The SauceLabs DesiredOption factory
https://github.com/sauceforge/saucery
automation c-sharp dotnet jenkins nunit saucelabs tdd test-driven-development testing xunit
Last synced: 20 days ago
JSON representation
The SauceLabs DesiredOption factory
- Host: GitHub
- URL: https://github.com/sauceforge/saucery
- Owner: Sauceforge
- License: mit
- Created: 2015-11-14T02:34:08.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2024-10-29T09:07:52.000Z (3 months ago)
- Last Synced: 2024-10-29T10:58:10.914Z (3 months ago)
- Topics: automation, c-sharp, dotnet, jenkins, nunit, saucelabs, tdd, test-driven-development, testing, xunit
- Language: C#
- Homepage: http://sauceforge.github.io
- Size: 6.26 MB
- Stars: 3
- Watchers: 1
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Saucery
Automated testing made more awesome[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge)](https://raw.githubusercontent.com/SauceForge/Saucery/master/LICENSE)
[![CI-CD](https://img.shields.io/github/actions/workflow/status/SauceForge/Saucery/pipeline.yml?style=for-the-badge)](https://github.com/SauceForge/Saucery/actions/workflows/pipeline.yml)Saucery handles all the plumbing required to integrate with SauceLabs, making writing tests a breeze. Saucery comes in multiple flavors supporting popular test frameworks.
### Dog food Status
We test Saucery itself on SauceLabs![![Build Status](https://app.saucelabs.com/buildstatus/saucefauge)](https://app.saucelabs.com/u/saucefauge)
## Getting Started
Saucery takes care of the plumbing required to talk to SauceLabs, so you only need to tell Saucery *what* you want. Saucery takes care of the *how*.
Your tests, of course, will be specific to your System Under Test. The ones specified below are provided as examples only.
### Initial Setup
These steps apply to all flavors:
1. You'll need a SauceLabs account. You can get a free trial account [here](https://saucelabs.com/sign-up).
1. If you want to run your tests locally you need to set 2 environment variables, SAUCE_USER_NAME and SAUCE_API_KEY
1. 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](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository).### NUnit
1. In your solution create a simple class library.
1. Add properties CopyLocalLockFileAssemblies and GenerateRuntimeConfigurationFiles to the top PropertyGroup of the project file and set them both to true.
1. Add a NuGet Reference to [Saucery](https://www.nuget.org/packages/Saucery) and [NUnit3TestAdapter](https://www.nuget.org/packages/NUnit3TestAdapter).Your Project file should look something like this:
```
net9.0
enable
enable
false
true
true
true
```
The ExternalMerlin.NUnit dogfood integration tests use the following template:
```
using NUnit.Framework;
using Saucery;
using Saucery.Core.Dojo;
using Saucery.Tests.Common.PageObjects;
using Shouldly;[assembly: LevelOfParallelism(4)]
namespace ExternalMerlin.NUnit;
[TestFixture]
[Parallelizable]
[TestFixtureSource(typeof(RequestedPlatformData))]
public class NuGetIntegrationTests(BrowserVersion browserVersion) : SauceryBase(browserVersion)
{
[Test]
[TestCase(5)]
[TestCase(4)]
public void DataDrivenTitleTest(int data) {
var guineaPigPage = new GuineaPigPage(SauceryDriver(), "https://saucelabs.com/");guineaPigPage.TypeField(SauceryDriver(), "comments", data.ToString());
Driver?.Title.ShouldContain("I am a page title - Sauce Labs");
}[Test]
public void ClickLinkTest() {
var guineaPigPage = new GuineaPigPage(SauceryDriver(), "https://saucelabs.com/");
// find and click the link on the page
guineaPigPage.ClickLink(SauceryDriver());// verify the browser was navigated to the correct page
Driver?.Url.ShouldContain("saucelabs.com/test-guinea-pig2.html");
}
}```
The above code will run *3* unit tests (1 ClickLink test and 2 DataDrivenTitle tests) on *all* the platforms you specify, in parallel.
#### Parallelism
- The Level of Parallelism is determined by the number of parallel threads you have paid for in your SauceLabs account.
- We recommend 1 less than your limit. Our OpenSauce account has 5 so we specify 4 in our internal testing.
- Parallism is optional so you can exclude the `[assembly: LevelOfParallelism(4)]` and `[Parallelizable]` lines if you wish.The other lines are mandatory. Let's break the key lines down.
```
[TestFixture]
[Parallelizable]
[TestFixtureSource(typeof(RequestedPlatformData))]
public class NuGetIntegrationTests(BrowserVersion browserVersion) : SauceryBase(browserVersion)
```You can call the class what you like but it must take a `BrowserVersion` as a parameter and subclass `SauceryBase`.
`[TestFixtureSource(typeof(RequestedPlatformData))]` is how you tell Saucery 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.OnDemand;
using Saucery.Core.OnDemand.Base;
using Saucery.Core.Util;namespace ExternalMerlin.NUnit;
public class RequestedPlatformData : SauceryTestData
{
static RequestedPlatformData()
{
List platforms =
[
//Real Devices
new AndroidRealDevice("Google Pixel 8 Pro", "14"),
new IOSRealDevice("iPhone 14 Pro Max", "16"),//Emulated Mobile Platforms
new AndroidPlatform("Google Pixel 8 Pro GoogleAPI Emulator", "14.0", SauceryConstants.DEVICE_ORIENTATION_PORTRAIT),
new IOSPlatform("iPhone 14 Pro Max Simulator", "16.2", SauceryConstants.DEVICE_ORIENTATION_LANDSCAPE),//Desktop Platforms
new DesktopPlatform(SauceryConstants.PLATFORM_LINUX, SauceryConstants.BROWSER_CHROME, SauceryConstants.BROWSER_VERSION_LATEST),
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_11, SauceryConstants.BROWSER_CHROME, "75"),
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_10, SauceryConstants.BROWSER_CHROME, "76", SauceryConstants.SCREENRES_2560_1600)
];SetPlatforms(platforms);
}
}
```The `List` is what you will specify. The rest of the class is mandatory. Check out `SauceryConstants` for all the platform, browser and screenres enums.
### XUnit
1. In your solution create a simple class library.
1. Add properties CopyLocalLockFileAssemblies and GenerateRuntimeConfigurationFiles to the top PropertyGroup of the project file and set them both to true.
1. Add a NuGet Reference to [Saucery.XUnit](https://www.nuget.org/packages/saucery.xunit) and [xunit.runner.visualstudio](https://www.nuget.org/packages/xunit.runner.visualstudio).Your Project file should look something like this:
```
net9.0
enable
enable
false
true
true
true
runtime; build; native; contentfiles; analyzers; buildtransitive
all
```
The ExternalMerlin.XUnit dogfood integration tests use the following template:
```
using Saucery.Core.Dojo;
using Saucery.Tests.Common.PageObjects;
using Saucery.XUnit;
using Xunit.Abstractions;[assembly: CollectionBehavior(MaxParallelThreads = 5)]
namespace ExternalMerlin.XUnit;
public class DataDrivenTests(ITestOutputHelper output, BaseFixture baseFixture) : SauceryXBase(output, baseFixture)
{
[Theory]
[MemberData(nameof(AllCombinations))]
public void DataDrivenTest(BrowserVersion requestedPlatform, int data)
{
InitialiseDriver(requestedPlatform);var guineaPigPage = new GuineaPigPage(BaseFixture.SauceryDriver(), "https://saucelabs.com/");
guineaPigPage.TypeField(BaseFixture.SauceryDriver(), "comments", data.ToString());
}public static IEnumerable AllCombinations => GetAllCombinations([4, 5]);
}
```The above code will run *2* unit tests (2 DataDrivenTitle tests) on *all* the platforms you specify.
#### Parallelism
- Parallelism in XUnit is currently achieved by having tests in multiple classes.
- The Level of Parallelism is determined by the number of parallel threads you have paid for in your SauceLabs account.
- Parallism is optional so you can exclude `[assembly: CollectionBehavior(MaxParallelThreads = 5)]` lines if you wish. We recommend placing this line in a `Usings.cs` as it will apply to all your TestFixtures.Next, let's break down the key line.
```
public class DataDrivenTests(ITestOutputHelper output, BaseFixture baseFixture) : SauceryXBase(output, baseFixture)
```Your class must subclass `SauceryXBase` and pass an `ITestOutputHelper` and a `BaseFixture`. SauceryX will take care of the rest.
You need to specify a class to tell SauceryX what platforms you want to test on. 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.OnDemand;
using Saucery.Core.OnDemand.Base;
using Saucery.Core.Util;namespace ExternalMerlin.XUnit;
public class RequestedPlatformData : SauceryTestData
{
static RequestedPlatformData()
{
List platforms =
[
//Real Devices
new AndroidRealDevice("Google Pixel 8 Pro", "14"),
new IOSRealDevice("iPhone 14 Pro Max", "16"),//Emulated Mobile Platforms
new AndroidPlatform("Google Pixel 8 Pro GoogleAPI Emulator", "14.0", SauceryConstants.DEVICE_ORIENTATION_PORTRAIT),
new IOSPlatform("iPhone 14 Pro Max Simulator", "16.2", SauceryConstants.DEVICE_ORIENTATION_LANDSCAPE),//Desktop Platforms
new DesktopPlatform(SauceryConstants.PLATFORM_LINUX, SauceryConstants.BROWSER_CHROME, SauceryConstants.BROWSER_VERSION_LATEST),
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_11, SauceryConstants.BROWSER_CHROME, "75"),
new DesktopPlatform(SauceryConstants.PLATFORM_WINDOWS_10, SauceryConstants.BROWSER_CHROME, "76", SauceryConstants.SCREENRES_2560_1600)
];SetPlatforms(platforms);
}public static IEnumerable AllPlatforms => GetAllPlatforms();
}
```The `List` is what you will specify. The rest of the class is mandatory. Check out `SauceryConstants` for all the platform, browser and screenres enums.
### TUnit
1. In your solution create a simple class library.
1. Add a NuGet Reference to [Saucery.TUnit](https://www.nuget.org/packages/Saucery.TUnit).Your Project file should look something like this:
```
net9.0
enable
enable
```
#### IDE Setup
Follow the instructions [here](https://thomhurst.github.io/TUnit/docs/tutorial-basics/running-your-tests#visual-studio) to set up your IDE.The ExternalMerlin.TUnit dogfood integration tests use the following template:
```
using Saucery.Core.Dojo;
using Saucery.Tests.Common.PageObjects;
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> 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 requestedPlatform, int data)
```You can call the class what you like but it must take a `Func` 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
{
//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);
}public static List> AllPlatforms() => GetAllPlatformsAsFunc();
```The `List` 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!## Flavors
### Saucery
[![NuGet version (Saucery)](https://img.shields.io/nuget/v/Saucery.svg?style=for-the-badge)](https://www.nuget.org/packages/Saucery/)### Saucery.XUnit
[![NuGet version (Saucery.XUnit)](https://img.shields.io/nuget/v/Saucery.XUnit.svg?style=for-the-badge)](https://www.nuget.org/packages/Saucery.XUnit/)### Saucery.TUnit
[![NuGet version (Saucery.TUnit)](https://img.shields.io/nuget/v/Saucery.TUnit.svg?style=for-the-badge)](https://www.nuget.org/packages/Saucery.TUnit/)## Resources
### Download statistics
![Nuget](https://img.shields.io/nuget/dt/Saucery.svg?label=Saucery%40nuget&style=for-the-badge)
![Nuget](https://img.shields.io/nuget/dt/Saucery.XUnit.svg?label=Saucery.XUnit%40nuget&style=for-the-badge)
![Nuget](https://img.shields.io/nuget/dt/Saucery.TUnit.svg?label=Saucery.TUnit%40nuget&style=for-the-badge)### Trends
[Nuget downloads](https://nugettrends.com/packages?months=24&ids=Saucery&ids=Saucery.XUnit&ids=Saucery.TUnit)
[GitHub stars](https://star-history.com/#sauceforge/Saucery)## Contact
Author: Andrew Gray
Twitter: [@agrayz](https://twitter.com/agrayz)