Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/motus-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
dotnet pack src/Motus.Recorder/Motus.Recorder.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
dotnet pack src/Motus.Testing/Motus.Testing.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
dotnet pack src/Motus.Testing.MSTest/Motus.Testing.MSTest.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
dotnet pack src/Motus.Testing.MSTest.v4/Motus.Testing.MSTest.v4.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
dotnet pack src/Motus.Testing.xUnit/Motus.Testing.xUnit.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
dotnet pack src/Motus.Testing.NUnit/Motus.Testing.NUnit.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
dotnet pack src/Motus.Cli/Motus.Cli.csproj -c Release -p:Version=${{ steps.version.outputs.version }} -o packages
Expand Down
30 changes: 30 additions & 0 deletions Motus.sln
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Motus.Mcp.Http", "src\Motus
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Motus.Testing.xUnit.Tests", "tests\Motus.Testing.xUnit.Tests\Motus.Testing.xUnit.Tests.csproj", "{C65BD8A2-DF4C-49C2-A070-8998E55D1C38}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Motus.Testing.MSTest.v4", "src\Motus.Testing.MSTest.v4\Motus.Testing.MSTest.v4.csproj", "{14C675DB-0985-4110-8DBE-585D5AD24571}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Motus.Testing.MSTest.v4.Tests", "tests\Motus.Testing.MSTest.v4.Tests\Motus.Testing.MSTest.v4.Tests.csproj", "{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -327,6 +331,30 @@ Global
{C65BD8A2-DF4C-49C2-A070-8998E55D1C38}.Release|x64.Build.0 = Release|Any CPU
{C65BD8A2-DF4C-49C2-A070-8998E55D1C38}.Release|x86.ActiveCfg = Release|Any CPU
{C65BD8A2-DF4C-49C2-A070-8998E55D1C38}.Release|x86.Build.0 = Release|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Debug|x64.ActiveCfg = Debug|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Debug|x64.Build.0 = Debug|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Debug|x86.ActiveCfg = Debug|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Debug|x86.Build.0 = Debug|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Release|Any CPU.Build.0 = Release|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Release|x64.ActiveCfg = Release|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Release|x64.Build.0 = Release|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Release|x86.ActiveCfg = Release|Any CPU
{14C675DB-0985-4110-8DBE-585D5AD24571}.Release|x86.Build.0 = Release|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Debug|x64.ActiveCfg = Debug|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Debug|x64.Build.0 = Debug|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Debug|x86.ActiveCfg = Debug|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Debug|x86.Build.0 = Debug|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Release|Any CPU.Build.0 = Release|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Release|x64.ActiveCfg = Release|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Release|x64.Build.0 = Release|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Release|x86.ActiveCfg = Release|Any CPU
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -354,6 +382,8 @@ Global
{110037A6-2F59-4273-B115-5047BDC39CE6} = {47F5729D-17CB-4046-88FA-BB0F9F660B6E}
{F2B42529-6278-4AC5-B1E4-49E55A95FDEA} = {C2BE1865-1543-4EBB-9E95-92EE083BF967}
{C65BD8A2-DF4C-49C2-A070-8998E55D1C38} = {47F5729D-17CB-4046-88FA-BB0F9F660B6E}
{14C675DB-0985-4110-8DBE-585D5AD24571} = {C2BE1865-1543-4EBB-9E95-92EE083BF967}
{88F3ADB4-C36D-4DDD-8976-0B4645EE0381} = {47F5729D-17CB-4046-88FA-BB0F9F660B6E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3A99AF87-BFA9-49CF-A20A-71753BE54A53}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The result is a framework that talks directly to Chromium and Firefox (CDP and W

```bash
dotnet add package Motus
dotnet add package Motus.Testing.MSTest # or Motus.Testing.xUnit / Motus.Testing.NUnit
dotnet add package Motus.Testing.MSTest.v4 # MSTest 4; or Motus.Testing.MSTest (MSTest 3) / Motus.Testing.xUnit / Motus.Testing.NUnit
dotnet tool install --global Motus.Cli
```

Expand Down Expand Up @@ -279,7 +279,7 @@ All CDP types are source-generated at build time from the protocol JSON schema.
| `Motus.Recorder` | Action capture, selector inference, POM generation |
| `Motus.Runner` | Blazor visual test runner with live screencast and timeline |
| `Motus.Cli` | `motus` CLI tool |
| `Motus.Testing.*` | Test framework integrations (MSTest, xUnit, NUnit) |
| `Motus.Testing.*` | Test framework integrations (MSTest 3 and 4, xUnit, NUnit) |

## The Extension Model

Expand Down
3 changes: 2 additions & 1 deletion docs/architecture/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Motus is a .NET browser automation framework that communicates directly with Chr
| `Motus.Runner` | Blazor visual test runner with live screencast and action timeline |
| `Motus.Cli` | `motus` CLI tool (`run`, `record`, `codegen`, `screenshot`, `pdf`, `trace`, `install`) |
| `Motus.Testing` | Shared base types for test framework integrations |
| `Motus.Testing.MSTest` | MSTest integration (`MotusTestBase`, lifecycle management) |
| `Motus.Testing.MSTest` | MSTest 3 integration (`MotusTestBase`, lifecycle management) |
| `Motus.Testing.MSTest.v4` | The same source built for MSTest 4 |
| `Motus.Testing.xUnit` | xUnit integration |
| `Motus.Testing.NUnit` | NUnit integration |
| `Motus.Samples` | Runnable usage examples |
Expand Down
3 changes: 2 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Add the Motus core package and the integration for your test framework:
dotnet add package Motus

# Pick one test framework integration
dotnet add package Motus.Testing.MSTest
dotnet add package Motus.Testing.MSTest.v4 # MSTest 4, which `dotnet new mstest` uses
dotnet add package Motus.Testing.MSTest # MSTest 3
dotnet add package Motus.Testing.NUnit
dotnet add package Motus.Testing.xUnit
```
Expand Down
13 changes: 12 additions & 1 deletion docs/guides/testing-frameworks.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,18 @@ Motus ships first-class test helpers for MSTest, NUnit, and xUnit. Each package

## MSTest

Package: `Motus.Testing.MSTest`
Package: `Motus.Testing.MSTest` for MSTest 3, `Motus.Testing.MSTest.v4` for MSTest 4

### MSTest 3 and MSTest 4

MSTest 4 renamed the assemblies its types live in, and MSTest recognizes an inherited `[TestInitialize]` or `[TestCleanup]` only by the exact identity of its own attribute types. A base class built against one major is invisible to a test project on the other: its setup and cleanup never run, and a test that touches `TestContext` does not compile. Motus therefore ships the MSTest integration twice, built from the same source:

| Your test project uses | Reference |
|---|---|
| MSTest 4.x, which `dotnet new mstest` creates | `Motus.Testing.MSTest.v4` |
| MSTest 3.x | `Motus.Testing.MSTest` |

Both packages use the namespace `Motus.Testing.MSTest` and contain the same types, so moving a suite from MSTest 3 to 4 changes the package reference and nothing in the tests. Reference one or the other, not both. `Motus.Testing.MSTest` accepts MSTest 3 only, so a project on MSTest 4 that references it gets a `NU1608` warning at restore rather than tests that quietly never get a page.

### MotusTestBase

Expand Down
4 changes: 3 additions & 1 deletion docs/migration/from-playwright.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,13 +386,15 @@ Environment variables prefixed with `MOTUS_` override individual config values a

### 1. Replace the NuGet package

Remove `Microsoft.Playwright` (and `Microsoft.Playwright.MSTest` if present). Add the Motus packages:
Remove `Microsoft.Playwright` (and `Microsoft.Playwright.MSTest` or `Microsoft.Playwright.MSTest.v4` if present). Add the Motus packages:

```xml
<PackageReference Include="Motus" Version="..." />
<PackageReference Include="Motus.Testing.MSTest" Version="..." />
```

On MSTest 4, reference `Motus.Testing.MSTest.v4` in place of `Motus.Testing.MSTest`, the way `Microsoft.Playwright.MSTest.v4` stands in for `Microsoft.Playwright.MSTest`. The namespace is `Motus.Testing.MSTest` in both.

### 2. Remove the Playwright CLI install step

Delete any `playwright install` or `pwsh bin/Debug/.../playwright.ps1 install` commands from your build scripts. Motus discovers the system browser or a browser installed via the Motus browser installer; there is no generated script to run.
Expand Down
2 changes: 1 addition & 1 deletion docs/migration/from-selenium.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ var page = await context.NewPageAsync();

**1. Remove WebDriver NuGet packages.**

Remove `Selenium.WebDriver`, `Selenium.WebDriver.ChromeDriver`, and any related packages. Add `Motus` and, if using MSTest, `Motus.Testing.MSTest`.
Remove `Selenium.WebDriver`, `Selenium.WebDriver.ChromeDriver`, and any related packages. Add `Motus` and, if using MSTest, `Motus.Testing.MSTest` (MSTest 3) or `Motus.Testing.MSTest.v4` (MSTest 4).

**2. Replace driver initialization.**

Expand Down
44 changes: 44 additions & 0 deletions src/Motus.Testing.MSTest.v4/Motus.Testing.MSTest.v4.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IsPackable>true</IsPackable>
<PackageId>Motus.Testing.MSTest.v4</PackageId>
<Title>Motus.Testing.MSTest.v4</Title>
<Description>MSTest 4 integration for Motus browser automation. Provides a base test class with per-test browser context isolation. For MSTest 3, use Motus.Testing.MSTest.</Description>
<IsTestProject>false</IsTestProject>
<!-- The same namespace as the MSTest 3 package, so moving between them is a package reference
and nothing in the tests. -->
<RootNamespace>Motus.Testing.MSTest</RootNamespace>
<DefineConstants>$(DefineConstants);MSTEST_V4</DefineConstants>
</PropertyGroup>

<!-- MSTest finds a base class's [TestInitialize] and [TestCleanup] by the exact identity of the
attribute type, and MSTest 4 renamed the assemblies those types live in. A base class built
against one major is invisible to a test project on the other, so this package is the
MSTest 3 package's source compiled a second time against MSTest 4. NuGet cannot choose a
build by the version of a dependency, which is why it is a package of its own rather than a
second build inside the first. -->
<ItemGroup>
<Compile Include="..\Motus.Testing.MSTest\**\*.cs"
Exclude="..\Motus.Testing.MSTest\bin\**;..\Motus.Testing.MSTest\obj\**"
LinkBase="Shared" />
<None Include="..\Motus.Testing.MSTest\README.md" Pack="true" PackagePath="\" Link="README.md" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Motus.Testing\Motus.Testing.csproj" />
<ProjectReference Include="..\Motus.Abstractions\Motus.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MSTest.TestFramework" Version="4.0.0" />
</ItemGroup>

</Project>
7 changes: 5 additions & 2 deletions src/Motus.Testing.MSTest/Motus.Testing.MSTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<IsPackable>true</IsPackable>
<PackageId>Motus.Testing.MSTest</PackageId>
<Title>Motus.Testing.MSTest</Title>
<Description>MSTest integration for Motus browser automation. Provides a base test class with per-test browser context isolation.</Description>
<Description>MSTest 3 integration for Motus browser automation. Provides a base test class with per-test browser context isolation. For MSTest 4, use Motus.Testing.MSTest.v4.</Description>
<IsTestProject>false</IsTestProject>
</PropertyGroup>

Expand All @@ -28,8 +28,11 @@
<ProjectReference Include="..\Motus.Abstractions\Motus.Abstractions.csproj" />
</ItemGroup>

<!-- Capped below 4: a base class built against MSTest 3 has its setup and cleanup ignored by
MSTest 4, so a project on 4 that picks this package up is told at restore (NU1608) rather
than by tests that never get a page. Motus.Testing.MSTest.v4 builds this source for 4. -->
<ItemGroup>
<PackageReference Include="MSTest.TestFramework" Version="3.5.2" />
<PackageReference Include="MSTest.TestFramework" Version="[3.5.2, 4.0.0)" />
</ItemGroup>

</Project>
54 changes: 54 additions & 0 deletions src/Motus.Testing.MSTest/MotusTestMethodAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
#if MSTEST_V4
using System.Runtime.CompilerServices;
#endif

// Motus has a test result of its own, for the runs its own runner reports. This file is about
// MSTest's, so the one name it borrows from Motus is named on its own.
Expand Down Expand Up @@ -27,6 +30,34 @@ public class MotusTestMethodAttribute : TestMethodAttribute
{
private readonly TestMethodAttribute? _inner;

#if MSTEST_V4
/// <summary>
/// Applies to a test method directly, in place of <c>[TestMethod]</c>.
/// </summary>
/// <remarks>
/// The caller's file and line are filled in by the compiler and passed on to MSTest, which uses
/// them to take the test explorer to the test's source.
/// </remarks>
public MotusTestMethodAttribute([CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1)
: base(callerFilePath, callerLineNumber)
{
}

/// <summary>
/// Wraps another kind of test method, so what that one does is kept and only the retry is added.
/// </summary>
/// <remarks>
/// Called from code rather than written on a method, so the source location is the wrapped
/// attribute's, not this constructor's caller.
/// </remarks>
#pragma warning disable MSTEST0057 // the location comes from the wrapped attribute
public MotusTestMethodAttribute(TestMethodAttribute? inner)
: base(inner?.DeclaringFilePath ?? "", inner?.DeclaringLineNumber ?? -1)
#pragma warning restore MSTEST0057
{
_inner = inner;
}
#else
/// <summary>
/// Applies to a test method directly, in place of <c>[TestMethod]</c>.
/// </summary>
Expand All @@ -41,12 +72,34 @@ public MotusTestMethodAttribute(TestMethodAttribute? inner)
{
_inner = inner;
}
#endif

/// <summary>
/// How many further attempts a lost browser is worth. Zero runs the test once, whatever happens.
/// </summary>
public int Retries { get; set; } = 1;

// MSTest 4 runs a test through ExecuteAsync, and MSTest 3 through Execute, which 4 removed.
#if MSTEST_V4
/// <inheritdoc />
public override async Task<TestResult[]> ExecuteAsync(ITestMethod testMethod)
{
// No ConfigureAwait(false): each attempt resumes on the context MSTest ran the first one
// on, which an attribute being wrapped may depend on.
var results = await RunAsync(testMethod);

for (int attempt = 1; attempt <= Retries && LostTheBrowser(results); attempt++)
{
AnnounceRetry(testMethod, attempt);
results = await RunAsync(testMethod);
}

return results;
}

private Task<TestResult[]> RunAsync(ITestMethod testMethod)
=> _inner is not null ? _inner.ExecuteAsync(testMethod) : base.ExecuteAsync(testMethod);
#else
/// <inheritdoc />
public override TestResult[] Execute(ITestMethod testMethod)
{
Expand All @@ -63,6 +116,7 @@ public override TestResult[] Execute(ITestMethod testMethod)

private TestResult[] Run(ITestMethod testMethod)
=> _inner is not null ? _inner.Execute(testMethod) : base.Execute(testMethod);
#endif

private static bool LostTheBrowser(TestResult[]? results)
=> results is not null && Array.Exists(results, result => BrowserFailure.IsBrowserLost(result.TestFailureException));
Expand Down
10 changes: 10 additions & 0 deletions src/Motus.Testing.MSTest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@ Provides `MotusTestBase`, a base class that shares a single browser across all t

## Installation

For MSTest 4, which `dotnet new mstest` creates:

```shell
dotnet add package Motus.Testing.MSTest.v4
```

For MSTest 3:

```shell
dotnet add package Motus.Testing.MSTest
```

The two packages are built from the same source for each MSTest major, with the same namespace and types, so moving between them changes the package reference and nothing in the tests. A base class built against one MSTest major has its setup and cleanup ignored by the other, which is why there are two.

## Quick Start

```csharp
Expand Down
2 changes: 1 addition & 1 deletion src/Motus.Testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ dotnet add package Motus.Testing

This package depends on [Motus](https://www.nuget.org/packages/Motus) and [Motus.Abstractions](https://www.nuget.org/packages/Motus.Abstractions). Most consumers should install one of the framework-specific packages instead:

- [Motus.Testing.MSTest](https://www.nuget.org/packages/Motus.Testing.MSTest)
- [Motus.Testing.MSTest](https://www.nuget.org/packages/Motus.Testing.MSTest) (MSTest 3) or [Motus.Testing.MSTest.v4](https://www.nuget.org/packages/Motus.Testing.MSTest.v4) (MSTest 4)
- [Motus.Testing.xUnit](https://www.nuget.org/packages/Motus.Testing.xUnit)
- [Motus.Testing.NUnit](https://www.nuget.org/packages/Motus.Testing.NUnit)
3 changes: 2 additions & 1 deletion src/Motus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ await page.Locator("a").ClickAsync();
| [Motus.Analyzers](https://www.nuget.org/packages/Motus.Analyzers) | Roslyn analyzers for common automation mistakes |
| [Motus.Recorder](https://www.nuget.org/packages/Motus.Recorder) | Record browser interactions and emit test code |
| [Motus.Testing](https://www.nuget.org/packages/Motus.Testing) | Shared browser fixture for test frameworks |
| [Motus.Testing.MSTest](https://www.nuget.org/packages/Motus.Testing.MSTest) | MSTest integration |
| [Motus.Testing.MSTest](https://www.nuget.org/packages/Motus.Testing.MSTest) | MSTest 3 integration |
| [Motus.Testing.MSTest.v4](https://www.nuget.org/packages/Motus.Testing.MSTest.v4) | MSTest 4 integration |
| [Motus.Testing.xUnit](https://www.nuget.org/packages/Motus.Testing.xUnit) | xUnit integration |
| [Motus.Testing.NUnit](https://www.nuget.org/packages/Motus.Testing.NUnit) | NUnit integration |
| [Motus.Cli](https://www.nuget.org/packages/Motus.Cli) | CLI for test execution, recording, and browser management |
31 changes: 31 additions & 0 deletions tests/Motus.Testing.MSTest.v4.Tests/LifecycleAttributeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Reflection;
using Motus.Testing.MSTest;

namespace Motus.Testing.MSTest.v4.Tests;

/// <summary>
/// MSTest finds an inherited <c>[TestInitialize]</c> and <c>[TestCleanup]</c>, and sets
/// <c>TestContext</c>, by the exact identity of its own types. These hold when the base class was
/// built against the MSTest this project runs on, and fail when it was built against another major.
/// </summary>
[TestClass]
public class LifecycleAttributeTests
{
[TestMethod]
public void SetupAndCleanup_AreMarkedWithThisMSTestsAttributes()
{
var setup = typeof(MotusTestBase).GetMethod(nameof(MotusTestBase.MotusTestInitialize));
var cleanup = typeof(MotusTestBase).GetMethod(nameof(MotusTestBase.MotusTestCleanup));

Assert.IsNotNull(setup?.GetCustomAttribute<TestInitializeAttribute>(), "MSTest would never run the setup");
Assert.IsNotNull(cleanup?.GetCustomAttribute<TestCleanupAttribute>(), "MSTest would never run the cleanup");
}

[TestMethod]
public void TheTestContextProperty_IsThisMSTestsTestContext()
{
var property = typeof(MotusTestBase).GetProperty(nameof(MotusTestBase.TestContext));

Assert.AreEqual(typeof(TestContext), property?.PropertyType);
}
}
Loading
Loading