Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source Generator: Initial Version #1300

Merged
merged 39 commits into from Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cfbe25f
feat: Automatically generate stub
linkdotnet Nov 24, 2023
3902714
refactor: Created internal generator project
linkdotnet Nov 25, 2023
b8f671f
feat: Create stub generator in public project
linkdotnet Nov 25, 2023
494e275
feat: Add simple test
linkdotnet Nov 25, 2023
7e5e75b
feat: First working versions
linkdotnet Nov 25, 2023
1e92d1a
feat: use a new function to invoke the generator
linkdotnet Nov 26, 2023
998064d
collect everything - then generate
linkdotnet Nov 26, 2023
29ff898
refactor: Code organization
linkdotnet Nov 26, 2023
be755a3
feat: Make the stub partial
linkdotnet Nov 26, 2023
27212f9
feat: Use the correct column
linkdotnet Nov 26, 2023
6828160
feat: Add more tests
linkdotnet Nov 26, 2023
408ef9a
add documentation
linkdotnet Nov 26, 2023
694d1a6
Don't use double stub
linkdotnet Nov 26, 2023
fd9c5bb
Moved extension method into generator
linkdotnet Nov 27, 2023
f4c3a31
Update readme
linkdotnet Nov 27, 2023
bf9ea5f
Added ability to take over parameter values
linkdotnet Nov 27, 2023
dd85a3d
refactor
linkdotnet Nov 27, 2023
daf1fb9
Use render tests instead of reflection
linkdotnet Nov 28, 2023
5263009
cleanup
linkdotnet Nov 28, 2023
038440e
Better docs
linkdotnet Nov 28, 2023
74274f7
use const string
linkdotnet Nov 28, 2023
518db57
Use AddStub instead of AddGeneratedStub
linkdotnet Nov 29, 2023
78d061a
fix: add @ to interceptor path
egil Nov 29, 2023
9101acf
refactor: move anglesharp generator tests into subfolder
egil Nov 29, 2023
57aa451
feat: Add generator for StubAttribute
linkdotnet Nov 29, 2023
91c59a6
feat: narrow predicate
linkdotnet Nov 30, 2023
8f82ef2
refactor: Nest less
linkdotnet Nov 30, 2023
d2f5bc6
docs: Added documentation for generators
linkdotnet Dec 1, 2023
1a0b895
Added NuGet infos
linkdotnet Dec 2, 2023
880b11b
chore: Update package
linkdotnet Dec 10, 2023
a8d93c4
docs: use correct nuget information in package
linkdotnet Dec 15, 2023
f9e5a3a
feat: use always latest patch-version
linkdotnet Dec 15, 2023
9332754
fix ci errors
linkdotnet Dec 15, 2023
d0e0e52
remove unused code
linkdotnet Dec 15, 2023
96cd0fb
Update tests/bunit.generators.tests/bunit.generators.tests.csproj
linkdotnet Dec 15, 2023
258e768
Rename attribute and use generic version
linkdotnet Dec 15, 2023
7660837
Use raw string literals
linkdotnet Dec 15, 2023
fbf48d2
Release generators on build
linkdotnet Dec 16, 2023
9d80573
docs: Added new package
linkdotnet Dec 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions Directory.Build.props
Expand Up @@ -2,11 +2,11 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup Label="Configuration variables">
<DotNet3Version>3.1.22</DotNet3Version>
<DotNet5Version>5.0.0</DotNet5Version>
<DotNet6Version>6.0.0</DotNet6Version>
<DotNet7Version>7.0.0</DotNet7Version>
<DotNet8Version>8.0.0</DotNet8Version>
<DotNet3Version>3.1.*</DotNet3Version>
<DotNet5Version>5.0.*</DotNet5Version>
<DotNet6Version>6.0.*</DotNet6Version>
<DotNet7Version>7.0.*</DotNet7Version>
<DotNet8Version>8.0.*</DotNet8Version>
</PropertyGroup>

<!-- Solution wide properties -->
Expand Down
9 changes: 8 additions & 1 deletion bunit.sln
Expand Up @@ -68,10 +68,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.web.query", "src\buni
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.web.query.tests", "tests\bunit.web.query.tests\bunit.web.query.tests.csproj", "{DE975A0C-0672-4248-913E-D267C1001801}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators", "src\bunit.generators\bunit.generators.csproj", "{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators.internal", "src\bunit.generators.internal\bunit.generators.internal.csproj", "{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators.tests", "tests\bunit.generators.tests\bunit.generators.tests.csproj", "{09046981-D9EC-4295-8502-721AC54E1F12}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.generators", "src\bunit.generators\bunit.generators.csproj", "{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -126,6 +128,10 @@ Global
{09046981-D9EC-4295-8502-721AC54E1F12}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09046981-D9EC-4295-8502-721AC54E1F12}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09046981-D9EC-4295-8502-721AC54E1F12}.Release|Any CPU.Build.0 = Release|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -144,6 +150,7 @@ Global
{DE975A0C-0672-4248-913E-D267C1001801} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
{09046981-D9EC-4295-8502-721AC54E1F12} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {24106918-1C86-4769-BDA6-9C80E64CD260}
Expand Down
84 changes: 84 additions & 0 deletions docs/site/docs/extensions/bunit-generators.md
@@ -0,0 +1,84 @@
---
uid: bunit-generators
title: bUnit Generators
---

# bUnit Generators

The `bunit.generators` package contains a set of source generators that can be used to generate code likes stubs for Blazor components. The generators are designed to be used with the [bUnit](https://github.com/bunit-dev/bunit) testing framework for Blazor components. To use the generators, you must install the `bunit.generators` NuGet package in test project.

This page will describe the generators and their usage.

## Component stub generator via `AddStub`

This generator adds the ability to automatically generate stubs for a given type with no setup involved. The generator sits on top of the already
present `AddStub` method.
This comes in handy, when dealing with 3rd party components that might need an extensive setup. Here a small example:

Given the following component
```razor
<ThirdPartyText Text="@count" />
<button @onclick="IncrementCount">Increase by one</button>
@code {
private int count;

private void IncrementCount()
{
count++;
}
}
```

If `ThirdPartyText` is a 3rd party component, that needs a lot of setup, it might be easier to just stub it out:

```csharp
[Fact]
public void Text_button_gets_initial_count()
{
// This call will automatically generate a stub for the ThirdPartyButton component
// with the name "ThirdPartyButtonStub"
ComponentFactories.AddStub<ThirdPartyText>();
var cut = Render<Counter>(@<Counter />);

cut.Find("button").Click();

// Retrieves the stub from the render tree and checks if the text is "1"
cut.FindComponent<ThirdPartyTextStub>().Instance.Text.Should().Be("1");
}
```

### Setup
To use the generator, the **Interceptor** feature has to be used inside the csproj file:

```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<!-- This line is required to enable the generator and interceptor -->
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Bunit</InterceptorsPreviewNamespaces>
```

Due to the usage of **Interceptors** the generator is only available for .NET 8.0 and above. The generator does create a `partial` class, so it can be extended with custom logic if needed.

## Component stub generator via `StubAttribute`

This generator adds the ability to automatically generate stubs for a given type via an attribute.
The general setup for the given component above looks like this:
```csharp
namespace MyTest;

public class FeatureTests : TestContext
{
[Fact]
public void Test()
{
ComponentFactories.Add<ThirdPartyText, ThirdPartyStub>();
...
}
}

[Stub(typeof(ThirdPartyText))]
internal partial class ThidPartyStub { }
```

Current limitations of this approach is that he stubbed type is not allowed to be nested inside the test class.
10 changes: 10 additions & 0 deletions docs/site/docs/extensions/index.md
@@ -0,0 +1,10 @@
---
uid: extensions
title: Extensions for bUnit
---

# Extensions for bUnit

This section covers the various extensions available for bUnit. These extensions are not part of the core bUnit package, but are instead available as separate NuGet packages. The extensions are listed below, and each has its own documentation page.

* **[bunit.generators](xref:bunit-generators)** - A set of source generators that can be used to generate code like stubs for Blazor components
3 changes: 3 additions & 0 deletions docs/site/docs/toc.md
Expand Up @@ -30,6 +30,9 @@
## [Faking IWebAssemblyHostEnvironment](xref:fake-webassemblyhostenvironment)
## [Testing with InputFile component](xref:input-file)

# [Extensions][xref:extensions]
## [bunit.generators](xref:bunit-generators)

# [Miscellaneous testing tips](xref:misc-test-tips)
# [External resources](xref:external-resources)
# [Contribute](xref:contribute)
Expand Down
4 changes: 4 additions & 0 deletions src/bunit.generators.internal/Directory.Build.props
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- here to stop props inheritance from folders above -->
</Project>
13 changes: 13 additions & 0 deletions src/bunit.generators.internal/README.md
@@ -0,0 +1,13 @@
# Tips for developing with the generator

When changing the source generator, to see the effect, clearing the build cache may be necessary:

```
dotnet build-server shutdown
```

A good way to quickly see if the generate is producing output:

```
dotnet build-server shutdown && dotnet clean && dotnet test -p:TargetFramework=net8.0
```
30 changes: 30 additions & 0 deletions src/bunit.generators.internal/bunit.generators.internal.csproj
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<RootNamespace>Bunit</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<EmbeddedResource Include="Web.AngleSharp\IElementWrapperFactory.cs" />
<EmbeddedResource Include="Web.AngleSharp\IElementWrapper.cs" />
<EmbeddedResource Include="Web.AngleSharp\WrapperBase.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="AngleSharp" Version="1.0.7" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Polyfill" Version="1.0.31">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
73 changes: 68 additions & 5 deletions src/bunit.generators/README.md
linkdotnet marked this conversation as resolved.
Show resolved Hide resolved
@@ -1,13 +1,76 @@
# Tips for developing with the generator
# bUnit Generators

When changing the source generator, to see the effect, clearing the build cache may be necessary:
This package contains source generators for bUnit, to make it easier and more convenient to write tests.

## `AddStub` Generator
This generator adds the ability to automatically generate stubs for a given type with no setup involved. The generator sits on top of the already
present `AddStub` method.
This comes in handy, when dealing with 3rd party components that might need an extensive setup. Here a small example:

Given the following component
```razor
<ThirdPartyText Text="@count" />
<button @onclick="IncrementCount">Increase by one</button>
@code {
private int count;

private void IncrementCount()
{
count++;
}
}
```
dotnet build-server shutdown

If `ThirdPartyText` is a 3rd party component, that needs a lot of setup, it might be easier to just stub it out:

```csharp
[Fact]
public void Text_button_gets_initial_count()
{
// This call will automatically generate a stub for the ThirdPartyButton component
// with the name "ThirdPartyButtonStub"
ComponentFactories.AddStub<ThirdPartyText>();
var cut = Render<Counter>(@<Counter />);

cut.Find("button").Click();

// Retrieves the stub from the render tree and checks if the text is "1"
cut.FindComponent<ThirdPartyTextStub>().Instance.Text.Should().Be("1");
}
```

A good way to quicky see if the generate is producing output:
### Setup
To use the generator, the **Interceptor** feature has to be used inside the csproj file:

```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<!-- This line is required to enable the generator and interceptor -->
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Bunit</InterceptorsPreviewNamespaces>
```
dotnet build-server shutdown && dotnet clean && dotnet test -p:TargetFramework=net8.0

This limits the usage to .NET 8 and above.

## `StubAttribute`
This generator adds the ability to automatically generate stubs for a given type via an attribute.
The general setup for the given component above looks like this:
```csharp
namespace MyTest;

public class FeatureTests : TestContext
{
[Fact]
public void Test()
{
ComponentFactories.Add<ThirdPartyText, ThirdPartyStub>();
...
}
}

[Stub(typeof(ThirdPartyText))]
internal partial class ThidPartyStub { }
```

Current limitations of this approach:
* The stubbed type is not allowed to be nested inside the test class.