Skip to content

Commit d27801f

Browse files
committed
refactor: moved component mocking preview to own lib
1 parent 83d491c commit d27801f

21 files changed

Lines changed: 192 additions & 129 deletions

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ dotnet_diagnostic.AsyncFixer01.severity = none # AsyncFixer01: Unnecessary async
478478
# Meziantou
479479
# https://www.meziantou.net/enforcing-asynchronous-code-good-practices-using-a-roslyn-analyzer.htm
480480
dotnet_diagnostic.MA0006.severity = suggestion # MA0006: use String.Equals
481+
dotnet_diagnostic.MA0007.severity = none # MA0007: Add a comma after the last value
481482
dotnet_diagnostic.MA0048.severity = silent # MA0048: File name must match type name
482483

483484
# Microsoft - Code Analysis

bunit.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".workflows", ".workflows",
5959
.github\workflows\verification.yml = .github\workflows\verification.yml
6060
EndProjectSection
6161
EndProject
62+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.web.mock", "src\bunit.web.mock\bunit.web.mock.csproj", "{3B51665F-E515-498A-8A82-BDB623089F9D}"
63+
EndProject
64+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.web.mock.tests", "tests\bunit.web.mock.tests\bunit.web.mock.tests.csproj", "{050E57C2-C28F-4A9A-B35F-5725068AEF80}"
65+
EndProject
6266
Global
6367
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6468
Debug|Any CPU = Debug|Any CPU
@@ -97,6 +101,14 @@ Global
97101
{4CAB561E-0AFF-4516-AB9B-981F94EF1E86}.Debug|Any CPU.Build.0 = Debug|Any CPU
98102
{4CAB561E-0AFF-4516-AB9B-981F94EF1E86}.Release|Any CPU.ActiveCfg = Release|Any CPU
99103
{4CAB561E-0AFF-4516-AB9B-981F94EF1E86}.Release|Any CPU.Build.0 = Release|Any CPU
104+
{3B51665F-E515-498A-8A82-BDB623089F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
105+
{3B51665F-E515-498A-8A82-BDB623089F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
106+
{3B51665F-E515-498A-8A82-BDB623089F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
107+
{3B51665F-E515-498A-8A82-BDB623089F9D}.Release|Any CPU.Build.0 = Release|Any CPU
108+
{050E57C2-C28F-4A9A-B35F-5725068AEF80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
109+
{050E57C2-C28F-4A9A-B35F-5725068AEF80}.Debug|Any CPU.Build.0 = Debug|Any CPU
110+
{050E57C2-C28F-4A9A-B35F-5725068AEF80}.Release|Any CPU.ActiveCfg = Release|Any CPU
111+
{050E57C2-C28F-4A9A-B35F-5725068AEF80}.Release|Any CPU.Build.0 = Release|Any CPU
100112
EndGlobalSection
101113
GlobalSection(SolutionProperties) = preSolution
102114
HideSolutionNode = FALSE
@@ -111,6 +123,8 @@ Global
111123
{7972A80F-30DC-4EF4-9294-7D4DD2965882} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
112124
{F61B8A55-3B5B-45FB-8E38-DBF9296B35C7} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
113125
{4CAB561E-0AFF-4516-AB9B-981F94EF1E86} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
126+
{3B51665F-E515-498A-8A82-BDB623089F9D} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
127+
{050E57C2-C28F-4A9A-B35F-5725068AEF80} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
114128
EndGlobalSection
115129
GlobalSection(ExtensibilityGlobals) = postSolution
116130
SolutionGuid = {24106918-1C86-4769-BDA6-9C80E64CD260}
Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#if NET5_0_OR_GREATER
22
using System;
3-
using System.Collections.Generic;
43
using Bunit.ComponentFactories;
5-
using Bunit.TestDoubles;
64
using Microsoft.AspNetCore.Components;
75

86
namespace Bunit
@@ -12,8 +10,6 @@ namespace Bunit
1210
/// </summary>
1311
public static class ComponentFactoryCollectionExtensions
1412
{
15-
private static readonly RenderFragment<IReadOnlyDictionary<string, object>> NoopReplacementTemplate = _ => _ => {};
16-
1713
/// <summary>
1814
/// Configures bUnit to replace all components of type <typeparamref name="TComponent"/> with a component
1915
/// of type <typeparamref name="TReplacementComponent"/>.
@@ -32,111 +28,7 @@ public static ComponentFactoryCollection Add<TComponent, TReplacementComponent>(
3228
factories.Add(new GenericComponentFactory<TComponent, TReplacementComponent>());
3329

3430
return factories;
35-
}
36-
37-
/// <summary>
38-
/// Configures bUnit to use replace all components of type <typeparamref name="TComponent"/> (including derived components)
39-
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
40-
/// </summary>
41-
/// <remarks>NOTE: This will replace any component of type <typeparamref name="TComponent"/> or components that derives/inherits from it.</remarks>
42-
/// <typeparam name="TComponent">The type of component to replace with a <see cref="Stub{TComponent}"/> component.</typeparam>
43-
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
44-
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
45-
public static ComponentFactoryCollection AddStub<TComponent>(this ComponentFactoryCollection factories) where TComponent : IComponent
46-
=> AddStub<TComponent>(factories, NoopReplacementTemplate);
47-
48-
/// <summary>
49-
/// Configures bUnit to use replace all components of type <typeparamref name="TComponent"/> (including derived components)
50-
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
51-
/// </summary>
52-
/// <remarks>NOTE: This will replace any component of type <typeparamref name="TComponent"/> or components that derives/inherits from it.</remarks>
53-
/// <typeparam name="TComponent">The type of component to replace with a <see cref="Stub{TComponent}"/> component.</typeparam>
54-
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
55-
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
56-
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
57-
public static ComponentFactoryCollection AddStub<TComponent>(
58-
this ComponentFactoryCollection factories,
59-
Func<IReadOnlyDictionary<string, object>, string> replacementTemplate)
60-
where TComponent : IComponent
61-
{
62-
return AddStub<TComponent>(
63-
factories,
64-
ps => b => b.AddMarkupContent(0, replacementTemplate(ps)));
65-
}
66-
67-
/// <summary>
68-
/// Configures bUnit to use replace all components of type <typeparamref name="TComponent"/> (including derived components)
69-
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
70-
/// </summary>
71-
/// <remarks>NOTE: This will replace any component of type <typeparamref name="TComponent"/> or components that derives/inherits from it.</remarks>
72-
/// <typeparam name="TComponent">The type of component to replace with a <see cref="Stub{TComponent}"/> component.</typeparam>
73-
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
74-
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
75-
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
76-
public static ComponentFactoryCollection AddStub<TComponent>(
77-
this ComponentFactoryCollection factories,
78-
RenderFragment<IReadOnlyDictionary<string, object>> replacementTemplate)
79-
where TComponent : IComponent
80-
{
81-
return AddStub(factories, CreatePredicate(typeof(TComponent)), replacementTemplate);
82-
83-
static Predicate<Type> CreatePredicate(Type componentTypeToStub)
84-
=> componentType => componentType == componentTypeToStub || componentType.IsAssignableTo(componentTypeToStub);
85-
}
86-
87-
/// <summary>
88-
/// Configures bUnit to use replace all components whose type make the <paramref name="componentTypePredicate"/> predicate return <c>true</c>
89-
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
90-
/// </summary>
91-
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
92-
/// <param name="componentTypePredicate">The predicate which decides if a component should be replaced with a <see cref="Stub{TComponent}"/> component.</param>
93-
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
94-
public static ComponentFactoryCollection AddStub(
95-
this ComponentFactoryCollection factories,
96-
Predicate<Type> componentTypePredicate)
97-
=> AddStub(
98-
factories,
99-
componentTypePredicate,
100-
NoopReplacementTemplate);
101-
102-
/// <summary>
103-
/// Configures bUnit to use replace all components whose type make the <paramref name="componentTypePredicate"/> predicate return <c>true</c>
104-
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
105-
/// </summary>
106-
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
107-
/// <param name="componentTypePredicate">The predicate which decides if a component should be replaced with a <see cref="Stub{TComponent}"/> component.</param>
108-
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
109-
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
110-
public static ComponentFactoryCollection AddStub(
111-
this ComponentFactoryCollection factories,
112-
Predicate<Type> componentTypePredicate,
113-
Func<IReadOnlyDictionary<string, object>, string> replacementTemplate)
114-
=> AddStub(
115-
factories,
116-
componentTypePredicate,
117-
ps => b => b.AddMarkupContent(0, replacementTemplate(ps)));
118-
119-
/// <summary>
120-
/// Configures bUnit to use replace all components whose type make the <paramref name="componentTypePredicate"/> predicate return <c>true</c>
121-
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
122-
/// </summary>
123-
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
124-
/// <param name="componentTypePredicate">The predicate which decides if a component should be replaced with a <see cref="Stub{TComponent}"/> component.</param>
125-
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
126-
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
127-
public static ComponentFactoryCollection AddStub(
128-
this ComponentFactoryCollection factories,
129-
Predicate<Type> componentTypePredicate,
130-
RenderFragment<IReadOnlyDictionary<string, object>> replacementTemplate)
131-
{
132-
if (factories is null)
133-
throw new ArgumentNullException(nameof(factories));
134-
if (componentTypePredicate is null)
135-
throw new ArgumentNullException(nameof(componentTypePredicate));
136-
137-
factories.Add(new StubComponentFactory(componentTypePredicate, replacementTemplate));
138-
return factories;
139-
}
31+
}
14032
}
14133
}
14234
#endif

src/bunit.core/bunit.core.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
</Description>
1515
</PropertyGroup>
1616

17+
<ItemGroup>
18+
<PackageReference Include="Nerdbank.GitVersioning" Version="3.4.244" PrivateAssets="All" />
19+
</ItemGroup>
20+
1721
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
1822
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(DotNet3Version)" />
1923
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(DotNet3Version)" />

src/bunit.template/bunit.template.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
<ContentTargetFolders>content</ContentTargetFolders>
2222
</PropertyGroup>
2323

24+
<ItemGroup>
25+
<PackageReference Include="Nerdbank.GitVersioning" Version="3.4.244" PrivateAssets="All" />
26+
</ItemGroup>
27+
2428
<ItemGroup>
2529
<Content Include="template\**\*" Exclude="template\**\bin\**;template\**\obj\**;template\**\.vs\**" />
2630
<Compile Remove="**\*" />

src/bunit.core/ComponentFactories/StubComponentFactory.cs renamed to src/bunit.web.mock/ComponentFactories/StubComponentFactory.cs

File renamed without changes.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Bunit.ComponentFactories;
4+
using Bunit.TestDoubles;
5+
using Microsoft.AspNetCore.Components;
6+
7+
namespace Bunit
8+
{
9+
/// <summary>
10+
/// Extension methods for using component doubles.
11+
/// </summary>
12+
public static class ComponentFactoryCollectionExtensions
13+
{
14+
private static readonly RenderFragment<IReadOnlyDictionary<string, object>> NoopReplacementTemplate = _ => _ => {};
15+
16+
/// <summary>
17+
/// Configures bUnit to use replace all components of type <typeparamref name="TComponent"/> (including derived components)
18+
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
19+
/// </summary>
20+
/// <remarks>NOTE: This will replace any component of type <typeparamref name="TComponent"/> or components that derives/inherits from it.</remarks>
21+
/// <typeparam name="TComponent">The type of component to replace with a <see cref="Stub{TComponent}"/> component.</typeparam>
22+
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
23+
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
24+
public static ComponentFactoryCollection AddStub<TComponent>(this ComponentFactoryCollection factories) where TComponent : IComponent
25+
=> AddStub<TComponent>(factories, NoopReplacementTemplate);
26+
27+
/// <summary>
28+
/// Configures bUnit to use replace all components of type <typeparamref name="TComponent"/> (including derived components)
29+
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
30+
/// </summary>
31+
/// <remarks>NOTE: This will replace any component of type <typeparamref name="TComponent"/> or components that derives/inherits from it.</remarks>
32+
/// <typeparam name="TComponent">The type of component to replace with a <see cref="Stub{TComponent}"/> component.</typeparam>
33+
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
34+
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
35+
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
36+
public static ComponentFactoryCollection AddStub<TComponent>(
37+
this ComponentFactoryCollection factories,
38+
Func<IReadOnlyDictionary<string, object>, string> replacementTemplate)
39+
where TComponent : IComponent
40+
{
41+
return AddStub<TComponent>(
42+
factories,
43+
ps => b => b.AddMarkupContent(0, replacementTemplate(ps)));
44+
}
45+
46+
/// <summary>
47+
/// Configures bUnit to use replace all components of type <typeparamref name="TComponent"/> (including derived components)
48+
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
49+
/// </summary>
50+
/// <remarks>NOTE: This will replace any component of type <typeparamref name="TComponent"/> or components that derives/inherits from it.</remarks>
51+
/// <typeparam name="TComponent">The type of component to replace with a <see cref="Stub{TComponent}"/> component.</typeparam>
52+
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
53+
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
54+
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
55+
public static ComponentFactoryCollection AddStub<TComponent>(
56+
this ComponentFactoryCollection factories,
57+
RenderFragment<IReadOnlyDictionary<string, object>> replacementTemplate)
58+
where TComponent : IComponent
59+
{
60+
return AddStub(factories, CreatePredicate(typeof(TComponent)), replacementTemplate);
61+
62+
static Predicate<Type> CreatePredicate(Type componentTypeToStub)
63+
=> componentType => componentType == componentTypeToStub || componentType.IsAssignableTo(componentTypeToStub);
64+
}
65+
66+
/// <summary>
67+
/// Configures bUnit to use replace all components whose type make the <paramref name="componentTypePredicate"/> predicate return <c>true</c>
68+
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
69+
/// </summary>
70+
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
71+
/// <param name="componentTypePredicate">The predicate which decides if a component should be replaced with a <see cref="Stub{TComponent}"/> component.</param>
72+
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
73+
public static ComponentFactoryCollection AddStub(
74+
this ComponentFactoryCollection factories,
75+
Predicate<Type> componentTypePredicate)
76+
=> AddStub(
77+
factories,
78+
componentTypePredicate,
79+
NoopReplacementTemplate);
80+
81+
/// <summary>
82+
/// Configures bUnit to use replace all components whose type make the <paramref name="componentTypePredicate"/> predicate return <c>true</c>
83+
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
84+
/// </summary>
85+
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
86+
/// <param name="componentTypePredicate">The predicate which decides if a component should be replaced with a <see cref="Stub{TComponent}"/> component.</param>
87+
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
88+
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
89+
public static ComponentFactoryCollection AddStub(
90+
this ComponentFactoryCollection factories,
91+
Predicate<Type> componentTypePredicate,
92+
Func<IReadOnlyDictionary<string, object>, string> replacementTemplate)
93+
=> AddStub(
94+
factories,
95+
componentTypePredicate,
96+
ps => b => b.AddMarkupContent(0, replacementTemplate(ps)));
97+
98+
/// <summary>
99+
/// Configures bUnit to use replace all components whose type make the <paramref name="componentTypePredicate"/> predicate return <c>true</c>
100+
/// with a <see cref="Stub{TComponent}"/> component in the render tree.
101+
/// </summary>
102+
/// <param name="factories">The bUnit <see cref="ComponentFactoryCollection"/> to configure.</param>
103+
/// <param name="componentTypePredicate">The predicate which decides if a component should be replaced with a <see cref="Stub{TComponent}"/> component.</param>
104+
/// <param name="replacementTemplate">Optional replacement template that will be used to render output instead of the stubbed out component.</param>
105+
/// <returns>A <see cref="ComponentFactoryCollection"/>.</returns>
106+
public static ComponentFactoryCollection AddStub(
107+
this ComponentFactoryCollection factories,
108+
Predicate<Type> componentTypePredicate,
109+
RenderFragment<IReadOnlyDictionary<string, object>> replacementTemplate)
110+
{
111+
if (factories is null)
112+
throw new ArgumentNullException(nameof(factories));
113+
if (componentTypePredicate is null)
114+
throw new ArgumentNullException(nameof(componentTypePredicate));
115+
116+
factories.Add(new StubComponentFactory(componentTypePredicate, replacementTemplate));
117+
return factories;
118+
}
119+
}
120+
}

src/bunit.core/TestDoubles/Components/CapturedParameterView{TComponent}.cs renamed to src/bunit.web.mock/TestDoubles/Components/CapturedParameterView{TComponent}.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#if NET5_0_OR_GREATER
21
using System;
32
using System.Collections;
43
using System.Collections.Generic;
@@ -75,7 +74,7 @@ public TValue Get<TValue>(Expression<Func<TComponent, TValue>> parameterSelector
7574
if (parameterSelector is null)
7675
throw new ArgumentNullException(nameof(parameterSelector));
7776

78-
if (!(parameterSelector.Body is MemberExpression memberExpression) || !(memberExpression.Member is PropertyInfo propInfoCandidate))
77+
if (parameterSelector.Body is not MemberExpression memberExpression || memberExpression.Member is not PropertyInfo propInfoCandidate)
7978
throw new ArgumentException($"The parameter selector '{parameterSelector}' does not resolve to a public property on the component '{typeof(TComponent)}'.", nameof(parameterSelector));
8079

8180
var propertyInfo = propInfoCandidate.DeclaringType != ComponentType
@@ -113,4 +112,3 @@ public static CapturedParameterView<TComponent> From(ParameterView parameters)
113112
=> new(parameters.ToDictionary());
114113
}
115114
}
116-
#endif

src/bunit.core/TestDoubles/Components/ComponentDoubleBase{TComponent}.cs renamed to src/bunit.web.mock/TestDoubles/Components/ComponentDoubleBase{TComponent}.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#if NET5_0_OR_GREATER
21
using System;
32
using System.Diagnostics.CodeAnalysis;
43
using System.Threading.Tasks;
@@ -49,4 +48,3 @@ protected virtual void BuildRenderTree(RenderTreeBuilder builder) { }
4948
void IComponent.Attach(RenderHandle renderHandle) => this.renderHandle = renderHandle;
5049
}
5150
}
52-
#endif

src/bunit.core/TestDoubles/Components/ParameterNotFoundException.cs renamed to src/bunit.web.mock/TestDoubles/Components/ParameterNotFoundException.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#if NET5_0_OR_GREATER
21
using System;
32
using System.Runtime.Serialization;
43

@@ -26,4 +25,3 @@ private ParameterNotFoundException(SerializationInfo info, StreamingContext cont
2625
}
2726
}
2827
}
29-
#endif

0 commit comments

Comments
 (0)