Skip to content

Commit

Permalink
Merge pull request #227 from Blazored/hexabit-main
Browse files Browse the repository at this point in the history
Adding bUnit tests
  • Loading branch information
pwelter34 authored May 28, 2024
2 parents 3f18c1f + 26f7112 commit b3cb16a
Show file tree
Hide file tree
Showing 27 changed files with 1,105 additions and 1 deletion.
17 changes: 17 additions & 0 deletions Blazored.FluentValidation.sln
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServer", "samples\Bla
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedModels", "samples\Shared\SharedModels\SharedModels.csproj", "{42276235-5139-41D6-923D-18B7EB5E3E44}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DACAA0DB-2B93-4FE1-9D21-F45A4E63A640}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazored.FluentValidation.Tests", "tests\Blazored.FluentValidation.Tests\Blazored.FluentValidation.Tests.csproj", "{C92DF59B-B760-4FCC-A34C-A4007529BCC5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -78,6 +82,18 @@ Global
{42276235-5139-41D6-923D-18B7EB5E3E44}.Release|x64.Build.0 = Release|Any CPU
{42276235-5139-41D6-923D-18B7EB5E3E44}.Release|x86.ActiveCfg = Release|Any CPU
{42276235-5139-41D6-923D-18B7EB5E3E44}.Release|x86.Build.0 = Release|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x64.ActiveCfg = Debug|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x64.Build.0 = Debug|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x86.ActiveCfg = Debug|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x86.Build.0 = Debug|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|Any CPU.Build.0 = Release|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x64.ActiveCfg = Release|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x64.Build.0 = Release|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x86.ActiveCfg = Release|Any CPU
{C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -86,6 +102,7 @@ Global
{8BC1065A-A71E-4568-8A67-9C3AF039F73A} = {D5C6DCA9-C2BD-4117-BCCC-19E36E8406AB}
{2459CF4B-6548-4031-B784-43E943E270A9} = {D5C6DCA9-C2BD-4117-BCCC-19E36E8406AB}
{42276235-5139-41D6-923D-18B7EB5E3E44} = {D5C6DCA9-C2BD-4117-BCCC-19E36E8406AB}
{C92DF59B-B760-4FCC-A34C-A4007529BCC5} = {DACAA0DB-2B93-4FE1-9D21-F45A4E63A640}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {42B22D99-6E59-4B30-88AD-B9CC07E0DA49}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ The second is when manually validating the model using the `Validate` or `Valida
```

## Access to full `ValidationFailure`
If you need details about the specifics of a validation result (e.g. its `Severity), you can access the result of the
If you need details about the specifics of a validation result (e.g. its `Severity`), you can access the result of the
last validation by calling the `GetFailuresFromLastValidation` method on the `FluentValidationValidator` component.

```razor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<EditForm
Model="@_person"
OnValidSubmit="ValidSubmit"
OnInvalidSubmit="InvalidSubmit">

@if (DisableAssemblyScanning is null)
{
<FluentValidationValidator />
}
else
{
<FluentValidationValidator DisableAssemblyScanning="DisableAssemblyScanning.Value" />
}

<ValidationSummary/>

<p>
<label>First name: </label>
<InputText name="@nameof(_person.FirstName)" @bind-Value="@_person.FirstName"/>
</p>

<button type="submit">Save</button>
</EditForm>

@code {
[Parameter] public bool? DisableAssemblyScanning { get; set; }
private readonly Person _person = new();

internal ValidationResultType Result { get; private set; } = ValidationResultType.Valid;

private void ValidSubmit() => Result = ValidationResultType.Valid;
private void InvalidSubmit() => Result = ValidationResultType.Error;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### What does this test?
This test checks if the assembly scanning works. It leverages, that this test
assembly does not register any `AbstractValidator` by default.

- Setting the `DisableAssemblyScanning` to `true` should not find any validators and ignore errors.
- Setting the `DisableAssemblyScanning` to `false` or not setting the attribute at all, should
find the validators in the assembly and validate normally.
- Setting the `DisableAssemblyScanning` to `true` and registering the validators manually should
find the validators and validate normally.
80 changes: 80 additions & 0 deletions tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using Blazored.FluentValidation.Tests.Model;

namespace Blazored.FluentValidation.Tests.AssemblyScanning;

public class Tests : TestContext
{
private readonly Fixture _fixture = new();

[Fact]
public void DisableAssemblyScanning_SetToTrue_NoValidationHappens()
{
// Arrange
var cut = RenderComponent<Component>(p => p.Add(c => c.DisableAssemblyScanning, true));
var person = _fixture.InvalidPerson();

// Act
cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
cut.Find("button").Click();

// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Valid);
}

[Fact]
public void DisableAssemblyScanning_SetToFalse_ValidationHappens()
{
// Arrange
var cut = RenderComponent<Component>(p => p.Add(c => c.DisableAssemblyScanning, false));
var person = _fixture.InvalidPerson();

// Act
cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
cut.Find("button").Click();

// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}

[Fact]
public void DisableAssemblyScanning_NotSet_ValidationHappens()
{
// Arrange
var cut = RenderComponent<Component>(p => p.Add(c => c.DisableAssemblyScanning, null));
var person = _fixture.InvalidPerson();

// Act
cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
cut.Find("button").Click();

// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}

[Fact]
public void DisableAssemblyScanning_SetToTrueButValidatorsRegistered_ValidationHappens()
{
// Arrange
Services.AddTransient<AbstractValidator<Person>, PersonValidator>();
var cut = RenderComponent<Component>(p => p.Add(c => c.DisableAssemblyScanning, null));
var person = _fixture.InvalidPerson();

// Act
cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
cut.Find("button").Click();

// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}

private class Fixture
{
public Person InvalidPerson() => new()
{
FirstName = "",
LastName = "Doe",
EmailAddress = "[email protected]",
Age = 30
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<EditForm
Model="@_person"
OnValidSubmit="ValidSubmit"
OnInvalidSubmit="InvalidSubmit">

<FluentValidationValidator/>
<ValidationSummary/>

<p>
<label>First name: </label>
<InputText name="@nameof(_person.FirstName)" @bind-Value="@_person.FirstName"/>
</p>

<p>
<label>Last name: </label>
<InputText name="@nameof(_person.LastName)" @bind-Value="@_person.LastName"/>
</p>

<p>
<label>Age: </label>
<InputNumber name="@nameof(_person.Age)" @bind-Value="@_person.Age"/>
</p>

<p>
<label>Email Address: </label>
<InputText name="@nameof(_person.EmailAddress)" @bind-Value="@_person.EmailAddress"/>
</p>

<p>
<label>Address Line 1: </label>
<InputText name="@nameof(_person.Address.Line1)" @bind-Value="@_person.Address!.Line1"/>
</p>

<button type="submit">Save</button>
</EditForm>

@code {
private readonly Person _person = new() { Address = new() };
internal ValidationResultType Result { get; private set; } = ValidationResultType.Valid;

private void ValidSubmit() => Result = ValidationResultType.Valid;
private void InvalidSubmit() => Result = ValidationResultType.Error;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### What does this test?
This test checks if the basic validation works.

- Does a valid model pass the validation?
- Do basic validation rules get picked up?
- Do validation errors get displayed correctly in the UI?
- Are nested rules validated correctly?
110 changes: 110 additions & 0 deletions tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using Blazored.FluentValidation.Tests.Model;

namespace Blazored.FluentValidation.Tests.BasicValidation;

public class Tests : TestContext
{
private readonly Fixture _fixture = new();

[Fact]
public void Validate_DataIsValid_ValidSubmit()
{
// Arrange
var cut = RenderComponent<Component>();
var person = _fixture.ValidPerson();

// Act
FillForm(cut, person);
cut.Find("button").Click();

// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Valid);
}

[Fact]
public void Validate_FirstNameMissing_InvalidSubmit()
{
// Arrange
var cut = RenderComponent<Component>();
var person = _fixture.ValidPerson() with { FirstName = string.Empty };

// Act
FillForm(cut, person);
cut.Find("button").Click();

// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}

[Fact]
public void Validate_FirstNameMissing_ValidationErrorsPresent()
{
// Arrange
var cut = RenderComponent<Component>();
var person = _fixture.ValidPerson() with { FirstName = string.Empty };

// Act
FillForm(cut, person);
cut.Find("button").Click();

// Assert
cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameRequired);
cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameRequired);
}

[Fact]
public void Validate_AgeTooOld_ValidationErrorsPresent()
{
// Arrange
var cut = RenderComponent<Component>();
var person = _fixture.ValidPerson() with { Age = 250 };

// Act
FillForm(cut, person);
cut.Find("button").Click();

// Assert
cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.AgeMax);
}

[Fact]
public void Validate_AddressLine1Missing_ValidationErrorsPresent()
{
// Arrange
var cut = RenderComponent<Component>();
var person = _fixture.ValidPerson() with { Address = new() { Line1 = string.Empty } };

// Act
FillForm(cut, person);
cut.Find("button").Click();

// Assert
cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(AddressValidator.Line1Required);
}

private static void FillForm(IRenderedComponent<Component> cut, Person person)
{
cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
cut.Find($"input[name={nameof(Person.LastName)}]").Change(person.LastName);
cut.Find($"input[name={nameof(Person.EmailAddress)}]").Change(person.EmailAddress);
cut.Find($"input[name={nameof(Person.Age)}]").Change(person.Age.ToString());
cut.Find($"input[name={nameof(Person.Address.Line1)}]").Change(person.Address!.Line1);
}

private class Fixture
{
public Person ValidPerson() => new()
{
FirstName = "John",
LastName = "Doe",
EmailAddress = "[email protected]",
Age = 30,
Address = new()
{
Line1 = "123 Main St",
Town = "Springfield",
Postcode = "12345"
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<Using Include="Bunit" />
<Using Include="Bunit.TestDoubles" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Xunit"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="bunit" Version="1.26.64" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Blazored.FluentValidation\Blazored.FluentValidation.csproj" />
</ItemGroup>



</Project>
Loading

0 comments on commit b3cb16a

Please sign in to comment.