Skip to content

Commit d52c8fa

Browse files
authored
Add docs on running live tests serially (Azure#33829)
* General clean-up of markdownlint issues * Add section on serial live tests
1 parent 4498686 commit d52c8fa

File tree

2 files changed

+58
-39
lines changed

2 files changed

+58
-39
lines changed

sdk/core/Azure.Core.TestFramework/README.md

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Using the TestFramework
2+
23
To start using the Test Framework, add a project reference using the alias `AzureCoreTestFramework` into your test `.csproj`:
34

45
``` xml
@@ -9,8 +10,8 @@ To start using the Test Framework, add a project reference using the alias `Azur
910
...
1011

1112
</Project>
12-
1313
```
14+
1415
As an example, see the [Template](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/template/Azure.Template/tests/Azure.Template.Tests.csproj#L15) project.
1516

1617
## Sync-async tests
@@ -30,7 +31,6 @@ public class ConfigurationLiveTests: ClientTestBase
3031
...,
3132
InstrumentClientOptions(
3233
new ConfigurationClientClientOptions())));
33-
}
3434

3535
public async Task DeleteSettingNotFound()
3636
{
@@ -50,7 +50,6 @@ When using sync-async tests with recorded tests two sessions files will be gener
5050

5151
You can disable the sync-forwarding for an individual test by applying the `[AsyncOnly]` attribute to the test method.
5252

53-
5453
__Limitation__: all method calls/properties that are being used have to be `virtual`.
5554

5655
## Test environment and live test resources
@@ -70,7 +69,7 @@ public class AppConfigurationTestEnvironment : TestEnvironment
7069
}
7170
```
7271

73-
**NOTE:** Make sure that variables containing secret values are not recorded or are sanitized.
72+
__NOTE:__ Make sure that variables containing secret values are not recorded or are sanitized.
7473

7574
To sanitize variables use the `options` parameter of `GetRecordedVariable`:
7675

@@ -147,31 +146,53 @@ public class AppConfigurationTestEnvironment : TestEnvironment
147146
}
148147
```
149148

149+
### Running live tests serially
150+
151+
By default, NUnit does not run tests within each assembly in parallel, but this be [configured](https://docs.nunit.org/articles/nunit/technical-notes/usage/Framework-Parallel-Test-Execution.html).
152+
Especially for unit tests, this is often desirable; however, live and [recorded tests](#recorded-tests) may run into some issues. Thus, by default, the `RecordedTestBase` described below is attributed
153+
as `[NonParallelizable]`.
154+
155+
However, when projects are built and tested in CIs, all projects are testing in parallel. This means, for example, you can have two or more assemblies running tests such as one backing up or restoring
156+
a resource while another assembly's tests are trying to use that resource. The service may return an error like HTTP 409.
157+
158+
To isolate one or more projects so that they are tested serially, add a _service.projects_ file to your service directory e.g., _sdk/keyvault/service.projects_ with content like the following to set the
159+
`TestInParallel` metadata to `false`:
160+
161+
```xml
162+
<Project>
163+
<ItemGroup>
164+
<ProjectReference Update="$(MSBuildThisFileDirectory)Azure.Security.KeyVault.Administration/tests/*.csproj">
165+
<TestInParallel>false</TestInParallel>
166+
</ProjectReference>
167+
</ItemGroup>
168+
</Project>
169+
```
170+
150171
## Test settings
151172

152173
Test settings can be configured via `.runsettings` files. See [nunit.runsettings](https://github.com/Azure/azure-sdk-for-net/blob/main/eng/nunit.runsettings) for available knobs.
153174

154175
There are two ways to work with `.runsettings`. Both are picked up by Visual Studio without restart.
176+
155177
- You can edit [nunit.runsettings](https://github.com/Azure/azure-sdk-for-net/blob/main/eng/nunit.runsettings) locally to achieve desired configuration.
156178
- You can prepare few copies of `.runsettings` by cloning [nunit.runsettings](https://github.com/Azure/azure-sdk-for-net/blob/main/eng/nunit.runsettings).
179+
157180
Load them in Visual Studio (`Test>Configure Run Settings` menu) and switch between them. This option requires setting an environment variable `AZURE_SKIP_DEFAULT_RUN_SETTINGS=true`.
158181

159182
## TokenCredential
160183

161184
If a test or sample uses `TokenCredential` to construct the client use `TestEnvironment.Credential` to retrieve it.
162185

163186
``` C#
164-
public abstract class KeysTestBase : RecordedTestBase<KeyVaultTestEnvironment>
165-
{
166-
internal KeyClient GetClient() =>
167-
InstrumentClient(
168-
new KeyClient(
169-
new Uri(TestEnvironment.KeyVaultUrl),TestEnvironment.Credential,
170-
InstrumentClientOptions(
171-
new KeyClientOptions())));
172-
}
173-
}
174-
187+
public abstract class KeysTestBase : RecordedTestBase<KeyVaultTestEnvironment>
188+
{
189+
internal KeyClient GetClient() =>
190+
InstrumentClient(
191+
new KeyClient(
192+
new Uri(TestEnvironment.KeyVaultUrl),TestEnvironment.Credential,
193+
InstrumentClientOptions(
194+
new KeyClientOptions())));
195+
}
175196
```
176197

177198
## Recorded tests
@@ -180,7 +201,6 @@ The test framework provides an ability to record HTTP requests and responses and
180201

181202
To use recorded test functionality inherit from `RecordedTestBase<T>` class and use `InstrumentClientOptions` method when creating the client instance. Pass the test environment class as a generic argument to `RecordedTestBase`.
182203

183-
184204
``` C#
185205
public class ConfigurationLiveTests: RecordedTestBase<AppConfigurationTestEnvironment>
186206
{
@@ -215,7 +235,7 @@ In development scenarios where it's required to change mode quickly without rest
215235
Recorded tests can be attributed with the `RecordedTestAttribute` in lieu of the standard `TestAttribute` to enable functionality to automatically re-record tests that fail due to recording session file mismatches.
216236
Tests that are auto-rerecorded will fail with the following error and succeed if re-run.
217237

218-
```
238+
```text
219239
Error Message:
220240
Test failed playback, but was successfully re-recorded (it should pass if re-run). Please copy updated recording to SessionFiles.
221241
```
@@ -233,6 +253,7 @@ public class ConfigurationLiveTests: RecordedTestBase<AppConfigurationTestEnviro
233253
}
234254
}
235255
```
256+
236257
In addition to the auto-rerecording functionality, using the RecordedTestAttribute also will automatically retry tests that fail due due to exceeding the global test time limit.
237258

238259
When running tests in `Live` or `Record` mode, the Test Framework will prompt you to create the live test resources required for the tests if you don't have environment variables or an env file containing the required variables needed for the tests. This means that you do not have to manually run the New-TestResources script when attempting to run live tests! The Test Framework will also attempt to automatically extend the expiration of the test resource resource group whenever live tests are run. If the resource group specified in your .env file or environment variable has already expired and thus been deleted, the framework will prompt you to create a new resource group just like it would if an env variable required by the test was missing.
@@ -244,19 +265,19 @@ When tests are run in recording mode, session records are saved to the project d
244265
### Sanitizing
245266

246267
Secrets that are part of requests, responses, headers, or connections strings should be sanitized before saving the record.
247-
**Do not check in session records containing secrets.** Common headers like `Authentication` are sanitized automatically, but if custom logic is required and/or if request or response body need to be sanitized, the `Sanitizer` property should be used as an extension point.
268+
__Do not check in session records containing secrets.__ Common headers like `Authentication` are sanitized automatically, but if custom logic is required and/or if request or response body need to be sanitized, the `Sanitizer` property should be used as an extension point.
248269

249270
For example:
250271

251272
```C#
252-
public class ConfigurationLiveTests: RecordedTestBase<AppConfigurationTestEnvironment>
273+
public class ConfigurationLiveTests: RecordedTestBase<AppConfigurationTestEnvironment>
274+
{
275+
public ConfigurationLiveTests()
253276
{
254-
public ConfigurationLiveTests()
255-
{
256-
SanitizedHeaders.Add("example-header");
257-
SanitizeQueryParameters.Add("example-query-parameter");
258-
}
277+
SanitizedHeaders.Add("example-header");
278+
SanitizeQueryParameters.Add("example-query-parameter");
259279
}
280+
}
260281
```
261282

262283
Another sanitization feature that is available involves sanitizing Json payloads.
@@ -265,21 +286,20 @@ By adding a [Json Path](https://www.newtonsoft.com/json/help/html/QueryJsonSelec
265286
By default, the following values are added to the `JsonPathSanitizers` to be sanitized: `primaryKey`, `secondaryKey`, `primaryConnectionString`, `secondaryConnectionString`, and `connectionString`.
266287

267288
```c#
268-
public class FormRecognizerLiveTests: RecordedTestBase<FormRecognizerTestEnvironment>
289+
public class FormRecognizerLiveTests: RecordedTestBase<FormRecognizerTestEnvironment>
290+
{
291+
public FormRecognizerLiveTests()
269292
{
270-
public FormRecognizerLiveTests()
271-
{
272-
JsonPathSanitizers.Add("$..accessToken");
273-
JsonPathSanitizers.Add("$..source");
274-
}
293+
JsonPathSanitizers.Add("$..accessToken");
294+
JsonPathSanitizers.Add("$..source");
275295
}
296+
}
276297
```
277298

278299
### Matching
279300

280301
When tests are run in `Playback` mode, the HTTP method, Uri, and headers are used to match the request to the recordings. Some headers change on every request and are not controlled by the client code and should be ignored during matching. Common headers like `Date`, `x-ms-date`, `x-ms-client-request-id`, `User-Agent`, `Request-Id` are ignored by default but if more headers need to be ignored, use the various matching properties to customize as needed.
281302

282-
283303
``` C#
284304
public class ConfigurationLiveTests: RecordedTestBase<AppConfigurationTestEnvironment>
285305
{
@@ -373,7 +393,7 @@ How it looks it the test explorer:
373393

374394
![image](https://user-images.githubusercontent.com/1697911/72942831-52c7ca00-3d29-11ea-9b7e-2e54198d800d.png)
375395

376-
**Note:** If test recordings are enabled, the recordings will be generated against the latests version of the service.
396+
__Note:__ If test recordings are enabled, the recordings will be generated against the latests version of the service.
377397

378398
## Support for an additional test parameter
379399

@@ -395,6 +415,7 @@ public class TableServiceLiveTestsBase : RecordedTestBase<TablesTestEnvironment>
395415
{
396416
_endpointType = endpointType;
397417
}
418+
}
398419
```
399420

400421
```c#
@@ -413,9 +434,10 @@ public class TableServiceLiveTestsBase : RecordedTestBase<TablesTestEnvironment>
413434
_serviceVersion = serviceVersion;
414435
_endpointType = endpointType;
415436
}
437+
}
416438
```
417439

418-
**Note:** Additional parameter options work with test recordings and will create differentiated SessionRecords test class directory names for each additional parameter option.
440+
__Note:__ Additional parameter options work with test recordings and will create differentiated SessionRecords test class directory names for each additional parameter option.
419441
For example:
420442

421443
`/SessionRecords/TableClientLiveTests(CosmosTable)/CreatedCustomEntitiesCanBeQueriedWithFiltersAsync.json`
@@ -449,7 +471,7 @@ To download and unpack all artifacts use the `Download-DevOpsRecordings.ps1` scr
449471

450472
The `Download-DevOpsRecordings.ps1` would wait for active runs to finish before retrieving artifacts unless `-NoWait` switch is used.
451473

452-
**NOTE:** these scripts require being signed in with Azure CLI (https://docs.microsoft.com/cli/azure/authenticate-azure-cli?view=azure-cli-latest) and access to the internal DevOps project (https://dev.azure.com/azure-sdk/internal/)
474+
__NOTE:__ these scripts require being [signed in with Azure CLI](https://docs.microsoft.com/cli/azure/authenticate-azure-cli?view=azure-cli-latest) and access to the [internal DevOps project](https://dev.azure.com/azure-sdk/internal/).
453475

454476
### Note on private/non-virtual fields in your clients (such as _clientDiagnostics) and InternalsVisibleTo
455477

@@ -490,8 +512,6 @@ There are various helpful classes that assist in writing tests for the Azure SDK
490512
[TestEnvVar](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core.TestFramework/src/TestEnvVar.cs) allows you to wrap a block of code with a using statement inside which the configured Environment variables will be set to your supplied values.
491513
It ensures that the existing value of any configured environment variables are preserved before they are set them and restores them outside the scope of the using block.
492514

493-
#### Example usage
494-
495515
```c#
496516
using (var _ = new TestEnvVar("AZURE_TENANT_ID", "foo"))
497517
{
@@ -507,8 +527,6 @@ using (var _ = new TestEnvVar("AZURE_TENANT_ID", "foo"))
507527
It ensures that the existing value of any configured switches are preserved before they are set them and restores them outside the scope of the using block.
508528
Note: Even if an `AppContext` switch was un-set prior to setting it via `TestAppContextSwitch`, it will be unset after leaving the scope of the using block.
509529

510-
#### Example usage
511-
512530
```c#
513531
var isSet = AppContext.TryGetSwitch("Azure.Core.Pipeline.DisableHttpWebRequestTransport", out val))
514532
// isSet is false
@@ -526,9 +544,9 @@ var isSet = AppContext.TryGetSwitch("Azure.Core.Pipeline.DisableHttpWebRequestTr
526544
```
527545

528546
### AsyncAssert
547+
529548
This type contains static helper methods that cover some of the gaps in NUnit when it comes to async assertions. For instance, attempting to assert that a specific exception is thrown using Assert.That, Assert.Throws, or Assert.ThrowsAsync all result in sync over async code, which can lead to test flakiness.
530549

531-
#### Example usage
532550
```c#
533551
ServiceBusException exception = await AsyncAssert.ThrowsAsync<ServiceBusException>(
534552
async () => await args.CompleteMessageAsync(message, args.CancellationToken));

sdk/synapse/Azure.ResourceManager.Synapse/tests/ScenarioTests/WorkspaceOperationTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public async Task Initialize()
2626

2727
[Test]
2828
[RecordedTest]
29+
[Ignore("https://github.com/Azure/azure-sdk-for-net/issues/33867")]
2930
public async Task TestWorkspaceLifeCycle()
3031
{
3132
// create workspace

0 commit comments

Comments
 (0)