33using System . Threading ;
44using System . Threading . Tasks ;
55using AutoMapper ;
6+ using FluentValidation ;
67using Microsoft . EntityFrameworkCore ;
8+ using Microsoft . Extensions . Logging ;
79using Microsoft . Extensions . Logging . Abstractions ;
810using NUnit . Framework ;
911using PathfinderHonorManager . DataAccess ;
1214using PathfinderHonorManager . Model ;
1315using PathfinderHonorManager . Service ;
1416using PathfinderHonorManager . Tests . Helpers ;
17+ using PathfinderHonorManager . Validators ;
18+ using Incoming = PathfinderHonorManager . Dto . Incoming ;
1519
1620namespace PathfinderHonorManager . Tests . Service
1721{
1822 public class ClubServiceTests
1923 {
24+ protected DbContextOptions < PathfinderContext > ContextOptions { get ; }
25+ private ClubService _clubService ;
26+ private List < Club > _clubs ;
27+ private IValidator < Incoming . ClubDto > _validator ;
28+
2029 public ClubServiceTests ( )
2130 {
2231 ContextOptions = new DbContextOptionsBuilder < PathfinderContext > ( )
2332 . UseInMemoryDatabase ( databaseName : "TestDb" )
2433 . Options ;
2534 }
2635
27- protected DbContextOptions < PathfinderContext > ContextOptions { get ; }
28-
29- private ClubService _clubService ;
30-
31- private List < Club > _clubs ;
32-
3336 [ SetUp ]
3437 public async Task SetUp ( )
3538 {
36- using ( var dbContext = new PathfinderContext ( ContextOptions ) )
37- {
38- await SeedDatabase ( dbContext ) ;
39- }
39+ using var dbContext = new PathfinderContext ( ContextOptions ) ;
40+ await DatabaseCleaner . CleanDatabase ( dbContext ) ;
41+ await SeedDatabase ( dbContext ) ;
4042 }
4143
4244 private async Task SeedDatabase ( PathfinderContext dbContext )
4345 {
4446 _clubs = new List < Club >
45- {
46- new Club
4747 {
48- ClubID = Guid . NewGuid ( ) ,
49- Name = "Test Club 1"
50- } ,
51- new Club
52- {
53- ClubID = Guid . NewGuid ( ) ,
54- Name = "Test Club 2"
55- } ,
56- new Club
57- {
58- ClubID = Guid . NewGuid ( ) ,
59- Name = "Test Club 3"
60- }
61- } ;
62-
48+ new Club
49+ {
50+ ClubID = Guid . NewGuid ( ) ,
51+ ClubCode = "TESTCLUB1" ,
52+ Name = "Test Club 1"
53+ } ,
54+ new Club
55+ {
56+ ClubID = Guid . NewGuid ( ) ,
57+ ClubCode = "TESTCLUB2" ,
58+ Name = "Test Club 2"
59+ }
60+ } ;
6361
6462 await dbContext . Clubs . AddRangeAsync ( _clubs ) ;
6563 await dbContext . SaveChangesAsync ( ) ;
@@ -70,26 +68,23 @@ public async Task GetAllAsync_ReturnsAllClubs()
7068 {
7169 var mapperConfiguration = new MapperConfiguration ( cfg => cfg . AddProfile < AutoMapperConfig > ( ) ) ;
7270 IMapper mapper = mapperConfiguration . CreateMapper ( ) ;
73-
7471 var logger = new NullLogger < ClubService > ( ) ;
7572
76- var validator = new DummyValidator < ClubDto > ( ) ;
77-
7873 using ( var dbContext = new PathfinderContext ( ContextOptions ) )
7974 {
80- _clubService = new ClubService ( dbContext , mapper , logger ) ;
75+ _validator = new ClubValidator ( dbContext ) ;
76+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
8177
8278 // Act
8379 CancellationToken token = new ( ) ;
8480 var result = await _clubService . GetAllAsync ( token ) ;
81+
8582 // Assert
8683 Assert . That ( result , Is . Not . Null ) ;
8784 Assert . That ( result . Count , Is . EqualTo ( _clubs . Count ) ) ;
8885 }
8986 }
9087
91- // ...
92-
9388 [ TestCase ( 0 ) ]
9489 public async Task GetByIdAsync_ClubExists_ReturnsClub ( int clubIndex )
9590 {
@@ -99,7 +94,8 @@ public async Task GetByIdAsync_ClubExists_ReturnsClub(int clubIndex)
9994
10095 using ( var dbContext = new PathfinderContext ( ContextOptions ) )
10196 {
102- _clubService = new ClubService ( dbContext , mapper , logger ) ;
97+ _validator = new ClubValidator ( dbContext ) ;
98+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
10399
104100 // Act
105101 CancellationToken token = new ( ) ;
@@ -122,7 +118,8 @@ public async Task GetByIdAsync_ClubDoesNotExist_ReturnsNull()
122118
123119 using ( var dbContext = new PathfinderContext ( ContextOptions ) )
124120 {
125- _clubService = new ClubService ( dbContext , mapper , logger ) ;
121+ _validator = new ClubValidator ( dbContext ) ;
122+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
126123
127124 // Act
128125 CancellationToken token = new ( ) ;
@@ -133,17 +130,165 @@ public async Task GetByIdAsync_ClubDoesNotExist_ReturnsNull()
133130 Assert . That ( result , Is . Null ) ;
134131 }
135132 }
133+
134+ [ TestCase ]
135+ public async Task CreateAsync_ValidClub_ReturnsCreatedClub ( )
136+ {
137+ var mapperConfiguration = new MapperConfiguration ( cfg => cfg . AddProfile < AutoMapperConfig > ( ) ) ;
138+ IMapper mapper = mapperConfiguration . CreateMapper ( ) ;
139+ var logger = new NullLogger < ClubService > ( ) ;
140+
141+ using ( var dbContext = new PathfinderContext ( ContextOptions ) )
142+ {
143+ _validator = new ClubValidator ( dbContext ) ;
144+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
145+
146+ // Act
147+ CancellationToken token = new ( ) ;
148+ var newClub = new Incoming . ClubDto
149+ {
150+ Name = "New Test Club" ,
151+ ClubCode = "NEWCLUB"
152+ } ;
153+
154+ var result = await _clubService . CreateAsync ( newClub , token ) ;
155+
156+ // Assert
157+ Assert . That ( result , Is . Not . Null ) ;
158+ Assert . That ( result . Name , Is . EqualTo ( newClub . Name ) ) ;
159+ Assert . That ( result . ClubCode , Is . EqualTo ( newClub . ClubCode ) ) ;
160+ Assert . That ( result . ClubID , Is . Not . EqualTo ( Guid . Empty ) ) ;
161+
162+ // Verify the club was added to the database
163+ var savedClub = await dbContext . Clubs . SingleOrDefaultAsync ( c => c . ClubCode == newClub . ClubCode ) ;
164+ Assert . That ( savedClub , Is . Not . Null ) ;
165+ Assert . That ( savedClub . Name , Is . EqualTo ( newClub . Name ) ) ;
166+ }
167+ }
168+
169+ [ TestCase ]
170+ public async Task CreateAsync_DuplicateClubCode_ThrowsValidationException ( )
171+ {
172+ var mapperConfiguration = new MapperConfiguration ( cfg => cfg . AddProfile < AutoMapperConfig > ( ) ) ;
173+ IMapper mapper = mapperConfiguration . CreateMapper ( ) ;
174+ var logger = new NullLogger < ClubService > ( ) ;
175+
176+ using ( var dbContext = new PathfinderContext ( ContextOptions ) )
177+ {
178+ _validator = new ClubValidator ( dbContext ) ;
179+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
180+
181+ // Act
182+ CancellationToken token = new ( ) ;
183+ var newClub = new Incoming . ClubDto
184+ {
185+ Name = "Duplicate Club" ,
186+ ClubCode = _clubs [ 0 ] . ClubCode // Using existing club code to trigger exception
187+ } ;
188+
189+ // Assert
190+ Assert . ThrowsAsync < ValidationException > ( ( ) =>
191+ _clubService . CreateAsync ( newClub , token ) ) ;
192+ }
193+ }
194+
195+ [ TestCase ( 0 ) ]
196+ public async Task UpdateAsync_ValidClub_ReturnsUpdatedClub ( int clubIndex )
197+ {
198+ var mapperConfiguration = new MapperConfiguration ( cfg => cfg . AddProfile < AutoMapperConfig > ( ) ) ;
199+ IMapper mapper = mapperConfiguration . CreateMapper ( ) ;
200+ var logger = new NullLogger < ClubService > ( ) ;
201+
202+ using ( var dbContext = new PathfinderContext ( ContextOptions ) )
203+ {
204+ _validator = new ClubValidator ( dbContext ) ;
205+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
206+
207+ // Act
208+ CancellationToken token = new ( ) ;
209+ var clubId = _clubs [ clubIndex ] . ClubID ;
210+ var updatedClub = new Incoming . ClubDto
211+ {
212+ Name = "Updated Club Name" ,
213+ ClubCode = "UPDATED"
214+ } ;
215+
216+ var result = await _clubService . UpdateAsync ( clubId , updatedClub , token ) ;
217+
218+ // Assert
219+ Assert . That ( result , Is . Not . Null ) ;
220+ Assert . That ( result . ClubID , Is . EqualTo ( clubId ) ) ;
221+ Assert . That ( result . Name , Is . EqualTo ( updatedClub . Name ) ) ;
222+ Assert . That ( result . ClubCode , Is . EqualTo ( updatedClub . ClubCode ) ) ;
223+
224+ // Verify the club was updated in the database
225+ var savedClub = await dbContext . Clubs . FindAsync ( clubId ) ;
226+ Assert . That ( savedClub , Is . Not . Null ) ;
227+ Assert . That ( savedClub . Name , Is . EqualTo ( updatedClub . Name ) ) ;
228+ Assert . That ( savedClub . ClubCode , Is . EqualTo ( updatedClub . ClubCode ) ) ;
229+ }
230+ }
231+
232+ [ TestCase ]
233+ public async Task UpdateAsync_NonExistentClub_ReturnsNull ( )
234+ {
235+ var mapperConfiguration = new MapperConfiguration ( cfg => cfg . AddProfile < AutoMapperConfig > ( ) ) ;
236+ IMapper mapper = mapperConfiguration . CreateMapper ( ) ;
237+ var logger = new NullLogger < ClubService > ( ) ;
238+
239+ using ( var dbContext = new PathfinderContext ( ContextOptions ) )
240+ {
241+ _validator = new ClubValidator ( dbContext ) ;
242+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
243+
244+ // Act
245+ CancellationToken token = new ( ) ;
246+ var nonExistentId = Guid . NewGuid ( ) ;
247+ var updatedClub = new Incoming . ClubDto
248+ {
249+ Name = "Non Existent Club" ,
250+ ClubCode = "NONEXIST"
251+ } ;
252+
253+ var result = await _clubService . UpdateAsync ( nonExistentId , updatedClub , token ) ;
254+
255+ // Assert
256+ Assert . That ( result , Is . Null ) ;
257+ }
258+ }
136259
260+ [ TestCase ( 0 ) ]
261+ public async Task UpdateAsync_DuplicateClubCode_ThrowsValidationException ( int clubIndex )
262+ {
263+ var mapperConfiguration = new MapperConfiguration ( cfg => cfg . AddProfile < AutoMapperConfig > ( ) ) ;
264+ IMapper mapper = mapperConfiguration . CreateMapper ( ) ;
265+ var logger = new NullLogger < ClubService > ( ) ;
266+
267+ using ( var dbContext = new PathfinderContext ( ContextOptions ) )
268+ {
269+ _validator = new ClubValidator ( dbContext ) ;
270+ _clubService = new ClubService ( dbContext , mapper , logger , _validator ) ;
271+
272+ // Act
273+ CancellationToken token = new ( ) ;
274+ var clubId = _clubs [ clubIndex ] . ClubID ;
275+ var updatedClub = new Incoming . ClubDto
276+ {
277+ Name = "Updated Club Name" ,
278+ ClubCode = _clubs [ 1 ] . ClubCode // Using another club's code to trigger duplicate exception
279+ } ;
280+
281+ // Assert
282+ Assert . ThrowsAsync < ValidationException > ( ( ) =>
283+ _clubService . UpdateAsync ( clubId , updatedClub , token ) ) ;
284+ }
285+ }
137286
138287 [ TearDown ]
139288 public async Task TearDown ( )
140289 {
141290 using var dbContext = new PathfinderContext ( ContextOptions ) ;
142-
143- dbContext . Clubs . RemoveRange ( ) ;
144-
145- await dbContext . SaveChangesAsync ( ) ;
291+ await DatabaseCleaner . CleanDatabase ( dbContext ) ;
146292 }
147293 }
148-
149294}
0 commit comments