Skip to content

Commit

Permalink
Introduce attributes to refine customizations (#71)
Browse files Browse the repository at this point in the history
Introduce customizations to narrow generated values
* [PickFromRange(-12, 7)] - only values from specified range should be generated,
* [PickFromValues(-1, 3, 6, 9)] - values should only be selected from those specified,
* [Except(5, 7)] - values from outside the specified list should be generated.
  • Loading branch information
piotrzajac authored Dec 5, 2023
1 parent f723e17 commit 63a6f5c
Show file tree
Hide file tree
Showing 49 changed files with 2,246 additions and 79 deletions.
63 changes: 61 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ An attribute that can be applied to parameters in an `AutoDataAttribute`-driven

This attribute allows to disable the generation of members marked as `virtual` on a decorated type wheres `IgnoreVirtualMembers` arguments of mocking attributes mentioned above disable such a generation for all types created by `IFixture`.

**Caution:** Order is important! Applying `IgnoreVirtualMembers` attribute to the subsequent paramater makes precedig parameters of the same type to have `virtual` properties populated and the particular parameter with the following ones of the same type to have `virtual` properties unpopulated.
**Caution:** Order is important! Applying `IgnoreVirtualMembers` attribute to the subsequent parameter makes preceding parameters of the same type to have `virtual` properties populated and the particular parameter with the following ones of the same type to have `virtual` properties unpopulated.

#### Example

Expand Down Expand Up @@ -192,7 +192,7 @@ An attribute that can be applied to parameters in an `AutoDataAttribute`-driven

- IncludeParameterType - indicates whether attribute target parameter `Type` should included as a first argument when creating customization; by default set to `false`

**Caution:** Order is important! Applying `CustomizeWith` attribute to the subsequent paramater makes precedig parameters of the same type to be created without specified customization and the particular parameter with the specified customization.
**Caution:** Order is important! Applying `CustomizeWith` attribute to the subsequent parameter makes preceding parameters of the same type to be created without specified customization and the particular parameter with the specified customization.

#### Example

Expand Down Expand Up @@ -285,6 +285,65 @@ public void CustomizeWithAttributeUsage(

***

## Data filtering attributes

The following attributes helps narrowing down data generation to specific values or omitting certain values.

For these attributes to work, they must be used in conjunction with other data generation attributes.

They can be applied to simple types and collections.

### Except

An attribute ensuring that values from outside the specified list will be generated.

#### Example

```csharp
[Theory]
[AutoData]
public void ExceptAttributeUsage(
[Except(DayOfWeek.Saturday, DayOfWeek.Sunday)] DayOfWeek workday)
{
Assert.True(workday is >= DayOfWeek.Monday and <= DayOfWeek.Friday);
}
```

### PickFromRange

An attribute ensuring that only values from specified range will be generated.

#### Example

```csharp
[Theory]
[AutoData]
public void RangeAttributeUsage(
[PickFromRange(11, 19)] int teenagerAge)
{
Assert.True(teenagerAge is > 11 and < 19);
}
```

### PickFromValues

An attribute ensuring that only values from the specified list will be generated.

#### Example

```csharp
[Theory]
[AutoData]
public void ValuesAttributeUsage(
[PickFromValues(DayOfWeek.Saturday, DayOfWeek.Sunday)] HashSet<DayOfWeek> weekend)
{
var weekendDays = new[] { DayOfWeek.Saturday, DayOfWeek.Sunday };
Assert.Equivalent(weekendDays, weekend);
}
```

***

## Tips and tricks

### Fixture injection
Expand Down
9 changes: 6 additions & 3 deletions src/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ roslynator_equals_token_new_line = after
roslynator_infinite_loop_style = while
roslynator_max_line_length = 500
roslynator_new_line_at_end_of_file = true
roslynator_new_line_before_while_in_do_statement = false
roslynator_new_line_before_while_in_do_statement = true
roslynator_null_conditional_operator_new_line = after
roslynator_null_check_style = pattern_matching
roslynator_object_creation_parentheses_style = include
Expand Down Expand Up @@ -1368,7 +1368,7 @@ dotnet_diagnostic.RCS1235.severity = warning
dotnet_diagnostic.RCS1236.severity = warning

# RCS1237: Use bit shift operator.
dotnet_diagnostic.RCS1237.severity = suggestion
dotnet_diagnostic.RCS1237.severity = none

# RCS1238: Avoid nested ?: operators.
dotnet_diagnostic.RCS1238.severity = suggestion
Expand Down Expand Up @@ -2176,6 +2176,9 @@ dotnet_diagnostic.CA1849.severity = warning
# CA1850: Prefer static 'HashData' method over 'ComputeHash'
dotnet_diagnostic.CA1850.severity = warning

# CA1859: Use concrete types when possible for improved performance
dotnet_diagnostic.CA1859.severity = suggestion

# CA2000: Dispose objects before losing scope
dotnet_diagnostic.CA2000.severity = warning
dotnet_code_quality.CA2000.excluded_symbol_names =
Expand Down Expand Up @@ -3284,7 +3287,7 @@ dotnet_diagnostic.SA1519.severity = error
dotnet_diagnostic.SA1520.severity = error
dotnet_diagnostic.SA1600.severity = none
dotnet_diagnostic.SA1601.severity = none
dotnet_diagnostic.SA1602.severity = error
dotnet_diagnostic.SA1602.severity = none
dotnet_diagnostic.SA1603.severity = error
dotnet_diagnostic.SA1604.severity = error
dotnet_diagnostic.SA1605.severity = error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit.Sdk;

[Collection("AutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class AutoMockDataAttributeTests
{
[Fact(DisplayName = "WHEN parameterless constructor is invoked THEN fixture and attribute provider are created")]
Expand All @@ -34,9 +34,9 @@ public void WhenParameterlessConstructorIsInvoked_ThenFixtureAndAttributeProvide
attribute.IgnoreVirtualMembers.Should().BeFalse();
}

[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
public void WhenGetDataIsInvoked_ThenFixtureIsConfiguredAndDataReturned(bool ignoreVirtualMembers)
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit.Sdk;

[Collection("InlineAutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class InlineAutoMockDataAttributeTests
{
[Fact(DisplayName = "WHEN parameterless constructor is invoked THEN has no values but fixture and attribute provider are created")]
Expand Down Expand Up @@ -67,9 +67,9 @@ public void GivenUninitializedValues_WhenConstructorIsInvoked_ThenHasNoValuesAnd
attribute.Values.Should().HaveCount(0);
}

[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
public void WhenGetDataIsInvoked_ThenFixtureIsConfiguredAndDataReturned(bool ignoreVirtualMembers)
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit;

[Collection("MemberAutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class MemberAutoMockDataAttributeTests
{
public static IEnumerable<object[]> TestData { get; } = new[]
Expand All @@ -42,8 +42,8 @@ public int TestMethod(int first, int second, int third, int fourth, IDisposable
return first + second + third + fourth;
}

[Theory(DisplayName = "WHEN constructor is invoked THEN has shared fixture")]
[AutoData]
[Theory(DisplayName = "WHEN constructor is invoked THEN has shared fixture")]
public void WhenConstructorIsInvoked_ThenHasSharedFixture(Fixture fixture)
{
// Arrange
Expand Down Expand Up @@ -80,9 +80,9 @@ public void GivenExistingMemberName_WhenGetDataIsInvoked_ThenAppropriateDataIsRe
}
}

[Theory(DisplayName = "GIVEN IgnoreVirtualMembers WHEN GetData is invoked THEN fixture is customized correctly")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "GIVEN IgnoreVirtualMembers WHEN GetData is invoked THEN fixture is customized correctly")]
public void GivenIgnoreVirtualMembers_WhenGetDataIsInvoked_ThenFixtureIsCustomizedCorrectly(bool ignoreVirtualMembers)
{
// Arrange
Expand Down Expand Up @@ -111,8 +111,8 @@ public void GivenIgnoreVirtualMembers_WhenGetDataIsInvoked_ThenFixtureIsCustomiz
customizations[1].Should().BeOfType<AutoFakeItEasyCustomization>();
}

[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to true THEN same fixture per data row is used.")]
[MemberAutoMockData(nameof(TestDataShareFixture), ShareFixture = true)]
[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to true THEN same fixture per data row is used.")]
public void GivenMemberAutoMockData_WhenShareFixtureIsSetToTrue_ThenSameFixturePerDataRowIsUsed(int index, ICustomization customization, IFixture fixture)
{
// Arrange
Expand All @@ -125,8 +125,8 @@ public void GivenMemberAutoMockData_WhenShareFixtureIsSetToTrue_ThenSameFixtureP
fixture.Customizations.Should().HaveCount(expectedCustomizationsCount + index);
}

[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to false THEN unique fixture per data row is created.")]
[MemberAutoMockData(nameof(TestDataDoNotShareFixture), ShareFixture = false)]
[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to false THEN unique fixture per data row is created.")]
public void GivenMemberAutoMockData_WhenShareFixtureIsSetToFalse_ThenUniqueFixturePerDataRowIsCreated(ICustomization customization, IFixture fixture)
{
// Arrange
Expand Down Expand Up @@ -162,8 +162,8 @@ public void GivenUninitializedMemberName_WhenConstructorIsInvoked_ThenExceptionI
Assert.Throws<ArgumentNullException>(() => new MemberAutoMockDataAttribute(memberName));
}

[Theory(DisplayName = "GIVEN test method has some member generated parameters WHEN test run THEN parameters are provided")]
[MemberAutoMockData(nameof(TestData))]
[Theory(DisplayName = "GIVEN test method has some member generated parameters WHEN test run THEN parameters are provided")]
public void GivenTestMethodHasSomeMemberGeneratedParameters_WhenTestRun_ThenParametersAreProvided(
int first,
int second,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit.Sdk;

[Collection("AutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class AutoMockDataAttributeTests
{
[Fact(DisplayName = "WHEN parameterless constructor is invoked THEN fixture and attribute provider are created")]
Expand All @@ -34,9 +34,9 @@ public void WhenParameterlessConstructorIsInvoked_ThenFixtureAndAttributeProvide
attribute.IgnoreVirtualMembers.Should().BeFalse();
}

[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
public void WhenGetDataIsInvoked_ThenFixtureIsConfiguredAndDataReturned(bool ignoreVirtualMembers)
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit.Sdk;

[Collection("InlineAutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class InlineAutoMockDataAttributeTests
{
[Fact(DisplayName = "WHEN parameterless constructor is invoked THEN has no values but fixture and attribute provider are created")]
Expand Down Expand Up @@ -67,9 +67,9 @@ public void GivenUninitializedValues_WhenConstructorIsInvoked_ThenHasNoValuesAnd
attribute.Values.Should().HaveCount(0);
}

[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
public void WhenGetDataIsInvoked_ThenFixtureIsConfiguredAndDataReturned(bool ignoreVirtualMembers)
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit;

[Collection("MemberAutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class MemberAutoMockDataAttributeTests
{
public static IEnumerable<object[]> TestData { get; } = new[]
Expand All @@ -42,8 +42,8 @@ public int TestMethod(int first, int second, int third, int fourth, IDisposable
return first + second + third + fourth;
}

[Theory(DisplayName = "WHEN constructor is invoked THEN has shared fixture")]
[AutoData]
[Theory(DisplayName = "WHEN constructor is invoked THEN has shared fixture")]
public void WhenConstructorIsInvoked_ThenHasSharedFixture(Fixture fixture)
{
// Arrange
Expand Down Expand Up @@ -80,9 +80,9 @@ public void GivenExistingMemberName_WhenGetDataIsInvoked_ThenAppropriateDataIsRe
}
}

[Theory(DisplayName = "GIVEN IgnoreVirtualMembers WHEN GetData is invoked THEN fixture is customized correctly")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "GIVEN IgnoreVirtualMembers WHEN GetData is invoked THEN fixture is customized correctly")]
public void GivenIgnoreVirtualMembers_WhenGetDataIsInvoked_ThenFixtureIsCustomizedCorrectly(bool ignoreVirtualMembers)
{
// Arrange
Expand Down Expand Up @@ -111,8 +111,8 @@ public void GivenIgnoreVirtualMembers_WhenGetDataIsInvoked_ThenFixtureIsCustomiz
customizations[1].Should().BeOfType<AutoMoqCustomization>();
}

[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to true THEN same fixture per data row is used.")]
[MemberAutoMockData(nameof(TestDataShareFixture), ShareFixture = true)]
[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to true THEN same fixture per data row is used.")]
public void GivenMemberAutoMockData_WhenShareFixtureIsSetToTrue_ThenSameFixturePerDataRowIsUsed(int index, ICustomization customization, IFixture fixture)
{
// Arrange
Expand All @@ -125,8 +125,8 @@ public void GivenMemberAutoMockData_WhenShareFixtureIsSetToTrue_ThenSameFixtureP
fixture.Customizations.Should().HaveCount(expectedCustomizationsCount + index);
}

[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to false THEN unique fixture per data row is created.")]
[MemberAutoMockData(nameof(TestDataDoNotShareFixture), ShareFixture = false)]
[Theory(DisplayName = "GIVEN MemberAutoMockData WHEN ShareFixture is set to false THEN unique fixture per data row is created.")]
public void GivenMemberAutoMockData_WhenShareFixtureIsSetToFalse_ThenUniqueFixturePerDataRowIsCreated(ICustomization customization, IFixture fixture)
{
// Arrange
Expand Down Expand Up @@ -162,8 +162,8 @@ public void GivenUninitializedMemberName_WhenConstructorIsInvoked_ThenExceptionI
Assert.Throws<ArgumentNullException>(() => new MemberAutoMockDataAttribute(memberName));
}

[Theory(DisplayName = "GIVEN test method has some member generated parameters WHEN test run THEN parameters are provided")]
[MemberAutoMockData(nameof(TestData))]
[Theory(DisplayName = "GIVEN test method has some member generated parameters WHEN test run THEN parameters are provided")]
public void GivenTestMethodHasSomeMemberGeneratedParameters_WhenTestRun_ThenParametersAreProvided(
int first,
int second,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit.Sdk;

[Collection("AutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class AutoMockDataAttributeTests
{
[Fact(DisplayName = "WHEN parameterless constructor is invoked THEN fixture and attribute provider are created")]
Expand All @@ -34,9 +34,9 @@ public void WhenParameterlessConstructorIsInvoked_ThenFixtureAndAttributeProvide
attribute.IgnoreVirtualMembers.Should().BeFalse();
}

[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
public void WhenGetDataIsInvoked_ThenFixtureIsConfiguredAndDataReturned(bool ignoreVirtualMembers)
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Xunit.Sdk;

[Collection("InlineAutoMockDataAttribute")]
[Trait("Category", "Attributes")]
[Trait("Category", "DataAttribute")]
public class InlineAutoMockDataAttributeTests
{
[Fact(DisplayName = "WHEN parameterless constructor is invoked THEN has no values but fixture and attribute provider are created")]
Expand Down Expand Up @@ -67,9 +67,9 @@ public void GivenUninitializedValues_WhenConstructorIsInvoked_ThenHasNoValuesAnd
attribute.Values.Should().HaveCount(0);
}

[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
[InlineAutoData(true)]
[InlineAutoData(false)]
[Theory(DisplayName = "WHEN GetData is invoked THEN fixture is configured and data returned")]
public void WhenGetDataIsInvoked_ThenFixtureIsConfiguredAndDataReturned(bool ignoreVirtualMembers)
{
// Arrange
Expand Down
Loading

0 comments on commit 63a6f5c

Please sign in to comment.