Skip to content

Commit bc86675

Browse files
committed
Use NSubstitute for testing custom specs.
1 parent cb19e9c commit bc86675

File tree

11 files changed

+185
-309
lines changed

11 files changed

+185
-309
lines changed

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<PackageVersion Include="Testcontainers.MsSql" Version="4.6.0" />
3232
<PackageVersion Include="Polyfill" Version="8.8.0" />
3333
<PackageVersion Include="FluentAssertions" Version="[7.2.0]" />
34+
<PackageVersion Include="NSubstitute" Version="5.3.0" />
3435
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
3536
<PackageVersion Include="xunit" Version="2.9.3" />
3637
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.4" />

tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeStringEvaluatorCustomSpecTests.cs

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public class IncludeStringEvaluatorCustomSpecTests(TestFactory factory) : Integr
88
[Fact]
99
public void QueriesMatch_GivenNoIncludeString()
1010
{
11-
var spec = new CustomSpecification<Store>();
11+
var spec = Substitute.For<ISpecification<Store>>();
1212

1313
var actual = _evaluator
1414
.GetQuery(DbContext.Stores, spec)
@@ -23,8 +23,11 @@ public void QueriesMatch_GivenNoIncludeString()
2323
[Fact]
2424
public void QueriesMatch_GivenIncludeString()
2525
{
26-
var spec = new CustomSpecification<Store>();
27-
spec.Includes.Add(nameof(Address));
26+
var spec = Substitute.For<ISpecification<Store>>();
27+
spec.IncludeStrings.Returns(
28+
[
29+
nameof(Address)
30+
]);
2831

2932
var actual = _evaluator
3033
.GetQuery(DbContext.Stores, spec)
@@ -40,9 +43,12 @@ public void QueriesMatch_GivenIncludeString()
4043
[Fact]
4144
public void QueriesMatch_GivenMultipleIncludeStrings()
4245
{
43-
var spec = new CustomSpecification<Store>();
44-
spec.Includes.Add(nameof(Address));
45-
spec.Includes.Add($"{nameof(Company)}.{nameof(Country)}");
46+
var spec = Substitute.For<ISpecification<Store>>();
47+
spec.IncludeStrings.Returns(
48+
[
49+
nameof(Address),
50+
$"{nameof(Company)}.{nameof(Country)}"
51+
]);
4652

4753
var actual = _evaluator
4854
.GetQuery(DbContext.Stores, spec)
@@ -55,35 +61,4 @@ public void QueriesMatch_GivenMultipleIncludeStrings()
5561

5662
actual.Should().Be(expected);
5763
}
58-
59-
public class CustomSpecification<T> : ISpecification<T>
60-
{
61-
public List<string> Includes { get; set; } = new();
62-
public List<WhereExpressionInfo<T>> Where { get; set; } = new();
63-
public List<SearchExpressionInfo<T>> Search { get; set; } = new();
64-
public IEnumerable<string> IncludeStrings => Includes;
65-
public IEnumerable<SearchExpressionInfo<T>> SearchCriterias => Search;
66-
public IEnumerable<WhereExpressionInfo<T>> WhereExpressions => Where;
67-
68-
public ISpecificationBuilder<T> Query => throw new NotImplementedException();
69-
public IEnumerable<OrderExpressionInfo<T>> OrderExpressions => throw new NotImplementedException();
70-
public IEnumerable<IncludeExpressionInfo> IncludeExpressions => throw new NotImplementedException();
71-
public Dictionary<string, object> Items => throw new NotImplementedException();
72-
public int Take => throw new NotImplementedException();
73-
public int Skip => throw new NotImplementedException();
74-
public Func<IEnumerable<T>, IEnumerable<T>>? PostProcessingAction => throw new NotImplementedException();
75-
public IEnumerable<string> QueryTags => throw new NotImplementedException();
76-
public bool CacheEnabled => throw new NotImplementedException();
77-
public string? CacheKey => throw new NotImplementedException();
78-
public bool AsTracking => throw new NotImplementedException();
79-
public bool AsNoTracking => throw new NotImplementedException();
80-
public bool AsSplitQuery => throw new NotImplementedException();
81-
public bool AsNoTrackingWithIdentityResolution => throw new NotImplementedException();
82-
public bool IgnoreQueryFilters => throw new NotImplementedException();
83-
public bool IgnoreAutoIncludes => throw new NotImplementedException();
84-
public IEnumerable<T> Evaluate(IEnumerable<T> entities)
85-
=> throw new NotImplementedException();
86-
public bool IsSatisfiedBy(T entity)
87-
=> throw new NotImplementedException();
88-
}
8964
}

tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/QueryTagEvaluatorCustomTests.cs

Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Tests.Evaluators;
1+
using Azure;
2+
3+
namespace Tests.Evaluators;
24

35
[Collection("SharedCollection")]
46
public class QueryTagEvaluatorCustomTests(TestFactory factory) : IntegrationTest(factory)
@@ -10,8 +12,8 @@ public void QueriesMatch_GivenTag()
1012
{
1113
var tag = "asd";
1214

13-
var spec = new CustomSpecification<Country>();
14-
spec.Tags.Add(tag);
15+
var spec = Substitute.For<ISpecification<Country>>();
16+
spec.QueryTags.Returns([tag]);
1517

1618
var actual = _evaluator.GetQuery(DbContext.Countries, spec)
1719
.ToQueryString();
@@ -29,9 +31,8 @@ public void QueriesMatch_GivenMultipleTags()
2931
var tag1 = "asd";
3032
var tag2 = "qwe";
3133

32-
var spec = new CustomSpecification<Country>();
33-
spec.Tags.Add(tag1);
34-
spec.Tags.Add(tag2);
34+
var spec = Substitute.For<ISpecification<Country>>();
35+
spec.QueryTags.Returns([tag1, tag2]);
3536

3637
var actual = _evaluator.GetQuery(DbContext.Countries, spec)
3738
.ToQueryString();
@@ -48,7 +49,7 @@ public void QueriesMatch_GivenMultipleTags()
4849
[Fact]
4950
public void DoesNothing_GivenNoTag()
5051
{
51-
var spec = new CustomSpecification<Country>();
52+
var spec = Substitute.For<ISpecification<Country>>();
5253

5354
var actual = _evaluator.GetQuery(DbContext.Countries, spec)
5455
.Expression
@@ -67,8 +68,8 @@ public void Applies_GivenSingleTag()
6768
{
6869
var tag = "asd";
6970

70-
var spec = new CustomSpecification<Country>();
71-
spec.Tags.Add(tag);
71+
var spec = Substitute.For<ISpecification<Country>>();
72+
spec.QueryTags.Returns([tag]);
7273

7374
var actual = _evaluator.GetQuery(DbContext.Countries, spec)
7475
.Expression
@@ -88,9 +89,8 @@ public void Applies_GivenTwoTags()
8889
var tag1 = "asd";
8990
var tag2 = "qwe";
9091

91-
var spec = new CustomSpecification<Country>();
92-
spec.Tags.Add(tag1);
93-
spec.Tags.Add(tag2);
92+
var spec = Substitute.For<ISpecification<Country>>();
93+
spec.QueryTags.Returns([tag1, tag2]);
9494

9595
var actual = _evaluator.GetQuery(DbContext.Countries, spec)
9696
.Expression
@@ -112,10 +112,8 @@ public void Applies_GivenMultipleTags()
112112
var tag2 = "qwe";
113113
var tag3 = "zxc";
114114

115-
var spec = new CustomSpecification<Country>();
116-
spec.Tags.Add(tag1);
117-
spec.Tags.Add(tag2);
118-
spec.Tags.Add(tag3);
115+
var spec = Substitute.For<ISpecification<Country>>();
116+
spec.QueryTags.Returns([tag1, tag2, tag3]);
119117

120118
var actual = _evaluator.GetQuery(DbContext.Countries, spec)
121119
.Expression
@@ -130,35 +128,4 @@ public void Applies_GivenMultipleTags()
130128

131129
actual.Should().Be(expected);
132130
}
133-
134-
public class CustomSpecification<T> : ISpecification<T>
135-
{
136-
public List<string> Tags { get; set; } = new();
137-
public List<WhereExpressionInfo<T>> Where { get; set; } = new();
138-
public List<SearchExpressionInfo<T>> Search { get; set; } = new();
139-
public IEnumerable<string> QueryTags => Tags;
140-
public IEnumerable<SearchExpressionInfo<T>> SearchCriterias => Search;
141-
public IEnumerable<WhereExpressionInfo<T>> WhereExpressions => Where;
142-
143-
public ISpecificationBuilder<T> Query => throw new NotImplementedException();
144-
public IEnumerable<OrderExpressionInfo<T>> OrderExpressions => throw new NotImplementedException();
145-
public IEnumerable<IncludeExpressionInfo> IncludeExpressions => throw new NotImplementedException();
146-
public IEnumerable<string> IncludeStrings => throw new NotImplementedException();
147-
public Dictionary<string, object> Items => throw new NotImplementedException();
148-
public int Take => throw new NotImplementedException();
149-
public int Skip => throw new NotImplementedException();
150-
public Func<IEnumerable<T>, IEnumerable<T>>? PostProcessingAction => throw new NotImplementedException();
151-
public bool CacheEnabled => throw new NotImplementedException();
152-
public string? CacheKey => throw new NotImplementedException();
153-
public bool AsTracking => throw new NotImplementedException();
154-
public bool AsNoTracking => throw new NotImplementedException();
155-
public bool AsSplitQuery => throw new NotImplementedException();
156-
public bool AsNoTrackingWithIdentityResolution => throw new NotImplementedException();
157-
public bool IgnoreQueryFilters => throw new NotImplementedException();
158-
public bool IgnoreAutoIncludes => throw new NotImplementedException();
159-
public IEnumerable<T> Evaluate(IEnumerable<T> entities)
160-
=> throw new NotImplementedException();
161-
public bool IsSatisfiedBy(T entity)
162-
=> throw new NotImplementedException();
163-
}
164131
}

tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SearchEvaluatorCustomSpecTests.cs

Lines changed: 26 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ public class SearchEvaluatorCustomSpecTests(TestFactory factory) : IntegrationTe
99
[Fact]
1010
public void QueriesMatch_GivenNoSearch()
1111
{
12-
var spec = new CustomSpecification<Store>();
13-
spec.Where.Add(new WhereExpressionInfo<Store>(x => x.Id > 0));
12+
var spec = Substitute.For<ISpecification<Store>>();
13+
spec.WhereExpressions.Returns(
14+
[
15+
new WhereExpressionInfo<Store>(x => x.Id > 0)
16+
]);
1417

1518
var actual = _evaluator.GetQuery(DbContext.Stores, spec)
1619
.ToQueryString();
@@ -26,9 +29,15 @@ public void QueriesMatch_GivenSingleSearch()
2629
{
2730
var storeTerm = "ab1";
2831

29-
var spec = new CustomSpecification<Store>();
30-
spec.Where.Add(new WhereExpressionInfo<Store>(x => x.Id > 0));
31-
spec.Search.Add(new SearchExpressionInfo<Store>(x => x.Name, $"%{storeTerm}%"));
32+
var spec = Substitute.For<ISpecification<Store>>();
33+
spec.WhereExpressions.Returns(
34+
[
35+
new WhereExpressionInfo<Store>(x => x.Id > 0)
36+
]);
37+
spec.SearchCriterias.Returns(
38+
[
39+
new SearchExpressionInfo<Store>(x => x.Name, $"%{storeTerm}%")
40+
]);
3241

3342
var actual = _evaluator.GetQuery(DbContext.Stores, spec)
3443
.ToQueryString();
@@ -48,12 +57,18 @@ public void QueriesMatch_GivenMultipleSearch()
4857
var countryTerm = "ab3";
4958
var streetTerm = "ab4";
5059

51-
var spec = new CustomSpecification<Store>();
52-
spec.Where.Add(new WhereExpressionInfo<Store>(x => x.Id > 0));
53-
spec.Search.Add(new SearchExpressionInfo<Store>(x => x.Name, $"%{storeTerm}%"));
54-
spec.Search.Add(new SearchExpressionInfo<Store>(x => x.Company.Name, $"%{companyTerm}%"));
55-
spec.Search.Add(new SearchExpressionInfo<Store>(x => x.Address.Street, $"%{streetTerm}%", 2));
56-
spec.Search.Add(new SearchExpressionInfo<Store>(x => x.Company.Country.Name, $"%{countryTerm}%", 3));
60+
var spec = Substitute.For<ISpecification<Store>>();
61+
spec.WhereExpressions.Returns(
62+
[
63+
new WhereExpressionInfo<Store>(x => x.Id > 0)
64+
]);
65+
spec.SearchCriterias.Returns(
66+
[
67+
new SearchExpressionInfo<Store>(x => x.Name, $"%{storeTerm}%"),
68+
new SearchExpressionInfo<Store>(x => x.Company.Name, $"%{companyTerm}%"),
69+
new SearchExpressionInfo<Store>(x => x.Address.Street, $"%{streetTerm}%", 2),
70+
new SearchExpressionInfo<Store>(x => x.Company.Country.Name, $"%{countryTerm}%", 3)
71+
]);
5772

5873
var actual = _evaluator.GetQuery(DbContext.Stores, spec)
5974
.ToQueryString();
@@ -67,34 +82,4 @@ public void QueriesMatch_GivenMultipleSearch()
6782

6883
actual.Should().Be(expected);
6984
}
70-
71-
public class CustomSpecification<T> : ISpecification<T>
72-
{
73-
public List<WhereExpressionInfo<T>> Where { get; set; } = new();
74-
public List<SearchExpressionInfo<T>> Search { get; set; } = new();
75-
public IEnumerable<SearchExpressionInfo<T>> SearchCriterias => Search;
76-
public IEnumerable<WhereExpressionInfo<T>> WhereExpressions => Where;
77-
78-
public ISpecificationBuilder<T> Query => throw new NotImplementedException();
79-
public IEnumerable<OrderExpressionInfo<T>> OrderExpressions => throw new NotImplementedException();
80-
public IEnumerable<IncludeExpressionInfo> IncludeExpressions => throw new NotImplementedException();
81-
public IEnumerable<string> IncludeStrings => throw new NotImplementedException();
82-
public Dictionary<string, object> Items => throw new NotImplementedException();
83-
public int Take => throw new NotImplementedException();
84-
public int Skip => throw new NotImplementedException();
85-
public Func<IEnumerable<T>, IEnumerable<T>>? PostProcessingAction => throw new NotImplementedException();
86-
public IEnumerable<string> QueryTags => throw new NotImplementedException();
87-
public bool CacheEnabled => throw new NotImplementedException();
88-
public string? CacheKey => throw new NotImplementedException();
89-
public bool AsTracking => throw new NotImplementedException();
90-
public bool AsNoTracking => throw new NotImplementedException();
91-
public bool AsSplitQuery => throw new NotImplementedException();
92-
public bool AsNoTrackingWithIdentityResolution => throw new NotImplementedException();
93-
public bool IgnoreQueryFilters => throw new NotImplementedException();
94-
public bool IgnoreAutoIncludes => throw new NotImplementedException();
95-
public IEnumerable<T> Evaluate(IEnumerable<T> entities)
96-
=> throw new NotImplementedException();
97-
public bool IsSatisfiedBy(T entity)
98-
=> throw new NotImplementedException();
99-
}
10085
}

tests/Ardalis.Specification.EntityFrameworkCore.Tests/GlobalUsings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
global using System.Threading.Tasks;
99
global using Tests.Fixture;
1010
global using Xunit;
11+
global using NSubstitute;

0 commit comments

Comments
 (0)