Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8438d77
Freshness Edit: dotnet content (#45365)
GitHubber17 Mar 20, 2025
6c43d6c
Removes a note saying that Http Resilience in experimental (#45444)
iliar-turdushev Mar 20, 2025
f4fa369
Replace marketplace GHA with forked version (#45447)
BillWagner Mar 20, 2025
23c0f85
Add footnote about Arm64 build of VS 2022 (#45448)
scottaddie Mar 20, 2025
ec685db
Full edit pass on day one content (#45376)
BillWagner Mar 20, 2025
59c7691
Added article Generate Unit Tests with Copilot (#44228)
sigmade Mar 20, 2025
39311c9
Bump the dotnet group (#45422)
dependabot[bot] Mar 20, 2025
d1470c0
Bump the dotnet group (#45421)
dependabot[bot] Mar 20, 2025
239ef23
Bump the dotnet group (#45420)
dependabot[bot] Mar 20, 2025
9284ba3
Bump MSTest (#45413)
dependabot[bot] Mar 20, 2025
3949c06
Bump the dotnet group (#45406)
dependabot[bot] Mar 20, 2025
9dec418
Bump actions/setup-dotnet from 4.3.0 to 4.3.1 (#45401)
dependabot[bot] Mar 20, 2025
48cdcf5
Bump the dotnet group (#45400)
dependabot[bot] Mar 20, 2025
887adbe
Bump MSTest.TestFramework (#45387)
dependabot[bot] Mar 20, 2025
b2d0b7e
Bump the dotnet group (#45386)
dependabot[bot] Mar 20, 2025
e44b66e
Update ai-templates-github-models.md (#45449)
nprorekhin Mar 20, 2025
c7b0e55
Add RHEL native aot dependencies (#45429)
agocke Mar 20, 2025
169f6d9
Convert to interpolated strings (other dirs under samples/snippets/cs…
gewarren Mar 20, 2025
0eca2fb
Use the tightened text from the earlier PR (#45427)
BillWagner Mar 20, 2025
f7c7339
Convert to interpolated strings (standard, code-analysis, ml) (#45440)
gewarren Mar 20, 2025
75412af
Mutation Testing (#44615)
sigmade Mar 20, 2025
debae25
Convert to interpolated strings (VS_Snippets_CLR directory) (#45433)
gewarren Mar 21, 2025
c284277
Convert to interpolated strings (VS_Snippets_CFX directory) (#45432)
gewarren Mar 21, 2025
4fe248d
Convert to interpolated strings (Misc, VBCSharp, Remoting, CLR_System…
gewarren Mar 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-orphaned-articles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-orphaned-articles
title: "Monthly chores: Delete orphaned articles"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-orphaned-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-orphaned-images
title: "Monthly chores: Delete orphaned images"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-orphaned-includes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-orphaned-includes
title: "Monthly chores: Delete orphaned include files"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-orphaned-snippets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-orphaned-snippets
title: "Monthly chores: Delete orphaned snippets"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-redirect-hops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-remove-hops
title: "Monthly chores: Remove redirect hops"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-relative-links.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-relative-links
title: "Monthly chores: Use relative links"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanrepo-replace-redirects.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Create the PR for the work done by the "clean repo" tool
- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: cleanrepo-replace-redirects
title: "Monthly chores: Replace redirect targets"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
dependabot-yml-path: ".github/dependabot.yml"
- name: Create pull request
if: github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet'
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: create-dependabotconfig-pull-request/patch
title: "Update dependabot.yml - automatically."
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/snippets5000.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
# Get the latest preview SDK (or sdk not installed by the runner)
- name: Setup .NET
if: ${{ env.DOTNET_DO_INSTALL == 'true' }}
uses: actions/setup-dotnet@3951f0dfe7a07e2313ec93c75700083e2005cbab #@4.3.0
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 #@4.3.1
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
dotnet-quality: ${{ env.DOTNET_QUALITY }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/whats-new.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
savedir: './docs/whats-new'

- name: create-pull-request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
uses: dotnet/actions-create-pull-request@v4

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 6: third-party GitHubAction not pinned by hash
Remediation tip: update your workflow using https://app.stepsecurity.io
Click Remediation section below for further remediation help
with:
branch: create-whatsnew-pull-request/patch
title: "What's new article"
Expand Down
2 changes: 1 addition & 1 deletion docs/ai/quickstarts/includes/ai-templates-github-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ The **AI Chat Web App** app is almost ready to go as soon as it's created. Howev
# [.NET CLI](#tab/configure-dotnet-cli)

```dotnetcli
dotnet user-secrets set AzureOpenAi:Endpoint <your-personal-access-token>
dotnet user-secrets set GitHubModels:Token <your-personal-access-token>
```

---
Expand Down
6 changes: 4 additions & 2 deletions docs/azure/configure-visual-studio.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Configure Visual Studio for Azure Development with .NET
description: This article helps you configure Visual Studio for Azure development including getting the right workloads installed and connecting Visual Studio to your Azure account.
ms.topic: conceptual
ms.custom: devx-track-dotnet, engagement-fy23
ms.date: 3/19/2025
ms.date: 3/20/2025
author: alexwolfmsft
ms.author: alexwolf
---
Expand All @@ -21,10 +21,12 @@ If you already have Visual Studio installed, you can skip this step.

## Install Azure workloads

Open Visual Studio Installer and validate that the workloads **Azure development** and **ASP.NET and web development** are installed. If either of these workloads isn't installed, select them to be installed.
Open Visual Studio Installer and validate that the workloads **Azure development**&dagger; and **ASP.NET and web development** are installed. If either of these workloads isn't installed, select them to be installed.

![Screenshot of the Visual Studio Installer showing the Azure development and ASP.NET and Web Development Workloads selected](./media/visual-studio-installer-azure-development.png)

&dagger;The **Azure development** workload is currently unavailable in the Windows 11 Arm64 build of Visual Studio 2022.

## Authenticate Visual Studio with Azure

[!INCLUDE [auth-visual-studio](sdk/includes/auth-visual-studio.md)]
Expand Down
2 changes: 1 addition & 1 deletion docs/core/deploying/native-aot/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The Native AOT deployment model uses an ahead-of-time compiler to compile IL to
- RHEL (8+)

```sh
sudo dnf install clang zlib-devel
sudo dnf install clang zlib-devel zlib-ng-devel zlib-ng-compat-devel
```

# [Ubuntu](#tab/linux-ubuntu)
Expand Down
6 changes: 3 additions & 3 deletions docs/core/install/windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ Visual Studio Code is a powerful and lightweight source code editor that runs on

This [WinGet configuration file](https://builds.dotnet.microsoft.com/dotnet/install/dotnet_basic_config_docs.winget) installs the latest .NET SDK, Visual Studio Code and the C# DevKit. If you already have any of them installed, WinGet will skip that step.

1. Download the file and double-click to run it.
1. Read the license agreement, type <kbd>y</kbd>, and select <kbd>Enter</kbd> when prompted to accept.
1. Be on the lookout for a flashing User Account Control (UAC) prompt in your Windows Taskbar, you may need to require administrator-level permissions to install.
01. Download the file and double-click to run it.
01. Read the license agreement, type <kbd>y</kbd>, and select <kbd>Enter</kbd> when prompted to accept.
01. If you get a flashing User Account Control (UAC) prompt in your Taskbar, allow the installation to continue.

Additionally, the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension will install .NET for you if it's not already installed.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/core/testing/media/create-unit-test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/core/testing/media/stryker-final-report.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/core/testing/media/stryker-first-report.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/core/testing/media/test-copilot-prompt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/core/testing/media/test-copilot-result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/core/testing/media/test-mehod-stub.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
172 changes: 172 additions & 0 deletions docs/core/testing/mutation-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
---
title: Mutation testing
author: sigmade
description: Learn about the Stryker.net tool for mutation testing, to evaluate the quality of your unit tests.
ms.date: 03/11/2025
---

# Mutation testing

Mutation testing is a way to evaluate the quality of our unit tests. For mutation testing, the **Stryker.NET** tool automatically performs mutations in your code, runs tests, and generates a detailed report with the results.

## Example test scenario

Consider a sample _PriceCalculator.cs_ class with a `Calculate` method that calculates the price, taking into account the discount.

```csharp
public class PriceCalculator
{
public decimal CalculatePrice(decimal price, decimal discountPercent)
{
if (price <= 0)
{
throw new ArgumentException("Price must be greater than zero.");
}

if (discountPercent < 0 || discountPercent > 100)
{
throw new ArgumentException("Discount percent must be between 0 and 100.");
}

var discount = price * (discountPercent / 100);
var discountedPrice = price - discount;

return Math.Round(discountedPrice, 2);
}
}
```

The preceding method is covered by the following unit tests:

```csharp
[Fact]
public void ApplyDiscountCorrectly()
{
decimal price = 100;
decimal discountPercent = 10;

var calculator = new PriceCalculator();

var result = calculator.CalculatePrice(price, discountPercent);

Assert.Equal(90.00m, result);
}

[Fact]
public void InvalidDiscountPercent_ShouldThrowException()
{
var calculator = new PriceCalculator();

Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, -1));
Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, 101));
}

[Fact]
public void InvalidPrice_ShouldThrowException()
{
var calculator = new PriceCalculator();

Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(-10, 10));
}
```

The preceding code highlights two projects, one for the service that acts as a `PriceCalculator` and the other is the test project.

## Install the global tool

First, install **Stryker.NET**.
To do this, you need to execute the command:

```dotnetcli
dotnet tool install -g dotnet-stryker
```

To run `stryker`, invoke it from the command line in the directory where the unit test project is located:

```dotnetcli
dotnet stryker
```

After the tests have run, a report is displayed in the console.

:::image type="content" source="media/stryker-console-report.png" lightbox="media/stryker-console-report.png" alt-text="Stryker console report":::

**Stryker.NET** saves a detailed HTML report in the StrykerOutput directory.

:::image type="content" source="media/stryker-first-report.png" lightbox="media/stryker-first-report.png" alt-text="Stryker first report":::

Now, consider what mutants are and what 'survived' and 'killed' mean. A mutant is a small change in your code that Stryker makes on purpose. The idea is simple: if your tests are good, they should catch the change and fail. If they still pass, your tests might not be strong enough.

In our example, a mutant will be the replacement of the expression `price <= 0`, for example, with `price < 0`, after which unit tests are run.

Stryker supports several types of mutations:

| Type | Description |
|--|--|
| Equivalent | The equivalent operator is used to replace an operator with its equivalent. For example, `x < y` becomes `x <= y`. |
| Arithmetic | The arithmetic operator is used to replace an arithmetic operator with its equivalent. For example, `x + y` becomes `x - y`. |
| String | The string operator is used to replace a string with its equivalent. For example, `"text"` becomes `""`. |
| Logical | The logical operator is used to replace a logical operator with its equivalent. For example, `x && y` becomes `x \|\| y`. |

For additional mutation types, see the [Stryker.NET: Mutations](https://stryker-mutator.io/docs/stryker-net/mutations) documentation.

## Incremental improvement

If, after changing your code, the unit tests pass successfully, then they aren't sufficiently robust, and the mutant survived.
After mutation testing, five mutants survive.

Let's add test data for boundary values and run mutation testing again.

```csharp
[Fact]
public void InvalidPrice_ShouldThrowException()
{
var calculator = new PriceCalculator();

// changed price from -10 to 0
Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(0, 10));
}

[Fact] // Added test for 0 and 100 discount
public void NoExceptionForZeroAnd100Discount()
{
var calculator = new PriceCalculator();

var exceptionWhen0 = Record.Exception(() => calculator.CalculatePrice(100, 0));
var exceptionWhen100 = Record.Exception(() => calculator.CalculatePrice(100, 100));

Assert.Null(exceptionWhen0);
Assert.Null(exceptionWhen100);
}
```

:::image type="content" source="media/stryker-second-report.png" lightbox="media/stryker-second-report.png" alt-text="Stryker second report":::

As you can see, after correcting the equivalent mutants, we only have string mutations left, which we can easily 'kill' by checking the text of the exception message.

```csharp
[Fact]
public void InvalidDiscountPercent_ShouldThrowExceptionWithCorrectMessage()
{
var calculator = new PriceCalculator();

var ex1 = Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, -1));
Assert.Equal("Discount percent must be between 0 and 100.", ex1.Message);

var ex2 = Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, 101));
Assert.Equal("Discount percent must be between 0 and 100.", ex2.Message);
}

[Fact]
public void InvalidPrice_ShouldThrowExceptionWithCorrectMessage()
{
var calculator = new PriceCalculator();

var ex = Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(0, 10));
Assert.Equal("Price must be greater than zero.", ex.Message);
}
```

:::image type="content" source="media/stryker-final-report.png" lightbox="media/stryker-final-report.png" alt-text="Stryker final report":::

Mutation testing helps to find opportunities to improve tests that make them more reliable. It forces you to check not only the 'happy path', but also complex boundary cases, reducing the likelihood of bugs in production.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.8.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.8.2" />
<PackageReference Include="MSTest.TestAdapter" Version="3.8.3" />
<PackageReference Include="MSTest.TestFramework" Version="3.8.3" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.8.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.8.2" />
<PackageReference Include="MSTest.TestAdapter" Version="3.8.3" />
<PackageReference Include="MSTest.TestFramework" Version="3.8.3" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Loading
Loading