Skip to content

Commit 4f756ba

Browse files
committed
test: Application 모듈 유닛/통합 테스트 코드 작성
1 parent 962aabb commit 4f756ba

File tree

9 files changed

+3235
-0
lines changed

9 files changed

+3235
-0
lines changed
Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
using FluentAssertions;
2+
using ProjectVG.Application.Models.Character;
3+
using ProjectVG.Application.Services.Character;
4+
using ProjectVG.Common.Exceptions;
5+
using ProjectVG.Tests.Application.Integration.TestBase;
6+
using ProjectVG.Tests.Application.TestUtilities;
7+
using Xunit;
8+
9+
namespace ProjectVG.Tests.Application.Integration
10+
{
11+
[Collection("ApplicationIntegration")]
12+
public class CharacterServiceIntegrationTests
13+
{
14+
private readonly ICharacterService _characterService;
15+
private readonly ApplicationIntegrationTestFixture _fixture;
16+
17+
public CharacterServiceIntegrationTests(ApplicationIntegrationTestFixture fixture)
18+
{
19+
_fixture = fixture;
20+
_characterService = fixture.GetService<ICharacterService>();
21+
}
22+
23+
#region Create and Retrieve Integration Tests
24+
25+
[Fact]
26+
public async Task CreateAndGetCharacterAsync_ShouldPersistAndRetrieveCharacter()
27+
{
28+
// Arrange
29+
await _fixture.ClearDatabaseAsync();
30+
var createCommand = TestDataBuilder.CreateCreateCharacterCommand(
31+
"Integration Test Character",
32+
"A character for integration testing",
33+
"Test Role");
34+
35+
// Act - Create
36+
var createdCharacter = await _characterService.CreateCharacterAsync(createCommand);
37+
38+
// Act - Retrieve
39+
var retrievedCharacter = await _characterService.GetCharacterByIdAsync(createdCharacter.Id);
40+
41+
// Assert
42+
retrievedCharacter.Should().NotBeNull();
43+
retrievedCharacter.Id.Should().Be(createdCharacter.Id);
44+
retrievedCharacter.Name.Should().Be(createCommand.Name);
45+
retrievedCharacter.Description.Should().Be(createCommand.Description);
46+
retrievedCharacter.Role.Should().Be(createCommand.Role);
47+
retrievedCharacter.IsActive.Should().Be(createCommand.IsActive);
48+
}
49+
50+
[Fact]
51+
public async Task CreateMultipleCharacters_GetAllCharactersAsync_ShouldReturnAllCharacters()
52+
{
53+
// Arrange
54+
await _fixture.ClearDatabaseAsync();
55+
var commands = new[]
56+
{
57+
TestDataBuilder.CreateCreateCharacterCommand("Character 1", "Description 1", "Role 1"),
58+
TestDataBuilder.CreateCreateCharacterCommand("Character 2", "Description 2", "Role 2"),
59+
TestDataBuilder.CreateCreateCharacterCommand("Character 3", "Description 3", "Role 3")
60+
};
61+
62+
// Act - Create characters
63+
var createdCharacters = new List<CharacterDto>();
64+
foreach (var command in commands)
65+
{
66+
var created = await _characterService.CreateCharacterAsync(command);
67+
createdCharacters.Add(created);
68+
}
69+
70+
// Act - Get all
71+
var allCharacters = await _characterService.GetAllCharactersAsync();
72+
73+
// Assert
74+
allCharacters.Should().HaveCount(3);
75+
allCharacters.Should().OnlyContain(c => createdCharacters.Any(cc => cc.Id == c.Id));
76+
}
77+
78+
#endregion
79+
80+
#region Update Integration Tests
81+
82+
[Fact]
83+
public async Task CreateUpdateAndRetrieveCharacterAsync_ShouldPersistChanges()
84+
{
85+
// Arrange
86+
await _fixture.ClearDatabaseAsync();
87+
var createCommand = TestDataBuilder.CreateCreateCharacterCommand("Original Name");
88+
var createdCharacter = await _characterService.CreateCharacterAsync(createCommand);
89+
90+
var updateCommand = TestDataBuilder.CreateUpdateCharacterCommand(
91+
"Updated Name",
92+
"Updated Description",
93+
"Updated Role",
94+
true); // Keep IsActive = true so character can be retrieved
95+
96+
// Act - Update
97+
var updatedCharacter = await _characterService.UpdateCharacterAsync(createdCharacter.Id, updateCommand);
98+
99+
// Act - Retrieve after update
100+
var retrievedCharacter = await _characterService.GetCharacterByIdAsync(createdCharacter.Id);
101+
102+
// Assert
103+
updatedCharacter.Should().NotBeNull();
104+
updatedCharacter.Id.Should().Be(createdCharacter.Id);
105+
updatedCharacter.Name.Should().Be(updateCommand.Name);
106+
updatedCharacter.Description.Should().Be(updateCommand.Description);
107+
updatedCharacter.Role.Should().Be(updateCommand.Role);
108+
updatedCharacter.IsActive.Should().Be(updateCommand.IsActive);
109+
110+
retrievedCharacter.Should().BeEquivalentTo(updatedCharacter);
111+
}
112+
113+
[Fact]
114+
public async Task UpdateNonExistentCharacter_ShouldThrowNotFoundException()
115+
{
116+
// Arrange
117+
await _fixture.ClearDatabaseAsync();
118+
var nonExistentId = Guid.NewGuid();
119+
var updateCommand = TestDataBuilder.CreateUpdateCharacterCommand();
120+
121+
// Act & Assert
122+
await Assert.ThrowsAsync<NotFoundException>(
123+
() => _characterService.UpdateCharacterAsync(nonExistentId, updateCommand));
124+
}
125+
126+
#endregion
127+
128+
#region Delete Integration Tests
129+
130+
[Fact]
131+
public async Task CreateDeleteAndTryRetrieveCharacterAsync_ShouldRemoveFromDatabase()
132+
{
133+
// Arrange
134+
await _fixture.ClearDatabaseAsync();
135+
var createCommand = TestDataBuilder.CreateCreateCharacterCommand("To Be Deleted");
136+
var createdCharacter = await _characterService.CreateCharacterAsync(createCommand);
137+
138+
// Verify character exists
139+
var existsBefore = await _characterService.CharacterExistsAsync(createdCharacter.Id);
140+
existsBefore.Should().BeTrue();
141+
142+
// Act - Delete
143+
await _characterService.DeleteCharacterAsync(createdCharacter.Id);
144+
145+
// Assert - Should not exist
146+
var existsAfter = await _characterService.CharacterExistsAsync(createdCharacter.Id);
147+
existsAfter.Should().BeFalse();
148+
149+
// Should throw when trying to retrieve
150+
await Assert.ThrowsAsync<NotFoundException>(
151+
() => _characterService.GetCharacterByIdAsync(createdCharacter.Id));
152+
}
153+
154+
[Fact]
155+
public async Task DeleteNonExistentCharacter_ShouldThrowNotFoundException()
156+
{
157+
// Arrange
158+
await _fixture.ClearDatabaseAsync();
159+
var nonExistentId = Guid.NewGuid();
160+
161+
// Act & Assert
162+
await Assert.ThrowsAsync<NotFoundException>(
163+
() => _characterService.DeleteCharacterAsync(nonExistentId));
164+
}
165+
166+
[Fact]
167+
public async Task DeleteCharacterFromMultipleCharacters_ShouldOnlyDeleteSpecificCharacter()
168+
{
169+
// Arrange
170+
await _fixture.ClearDatabaseAsync();
171+
var character1 = await _characterService.CreateCharacterAsync(
172+
TestDataBuilder.CreateCreateCharacterCommand("Character 1"));
173+
var character2 = await _characterService.CreateCharacterAsync(
174+
TestDataBuilder.CreateCreateCharacterCommand("Character 2"));
175+
var character3 = await _characterService.CreateCharacterAsync(
176+
TestDataBuilder.CreateCreateCharacterCommand("Character 3"));
177+
178+
// Act - Delete middle character
179+
await _characterService.DeleteCharacterAsync(character2.Id);
180+
181+
// Assert
182+
var allCharacters = await _characterService.GetAllCharactersAsync();
183+
allCharacters.Should().HaveCount(2);
184+
allCharacters.Should().Contain(c => c.Id == character1.Id);
185+
allCharacters.Should().Contain(c => c.Id == character3.Id);
186+
allCharacters.Should().NotContain(c => c.Id == character2.Id);
187+
}
188+
189+
#endregion
190+
191+
#region Character Exists Integration Tests
192+
193+
[Fact]
194+
public async Task CharacterExistsAsync_WithExistingCharacter_ShouldReturnTrue()
195+
{
196+
// Arrange
197+
await _fixture.ClearDatabaseAsync();
198+
var createCommand = TestDataBuilder.CreateCreateCharacterCommand("Existing Character");
199+
var createdCharacter = await _characterService.CreateCharacterAsync(createCommand);
200+
201+
// Act
202+
var exists = await _characterService.CharacterExistsAsync(createdCharacter.Id);
203+
204+
// Assert
205+
exists.Should().BeTrue();
206+
}
207+
208+
[Fact]
209+
public async Task CharacterExistsAsync_WithNonExistentCharacter_ShouldReturnFalse()
210+
{
211+
// Arrange
212+
await _fixture.ClearDatabaseAsync();
213+
var nonExistentId = Guid.NewGuid();
214+
215+
// Act
216+
var exists = await _characterService.CharacterExistsAsync(nonExistentId);
217+
218+
// Assert
219+
exists.Should().BeFalse();
220+
}
221+
222+
#endregion
223+
224+
#region Complex Scenarios Integration Tests
225+
226+
[Fact]
227+
public async Task CompleteCharacterLifecycle_ShouldWorkCorrectly()
228+
{
229+
// Arrange
230+
await _fixture.ClearDatabaseAsync();
231+
232+
// Create
233+
var createCommand = TestDataBuilder.CreateCreateCharacterCommand("Lifecycle Character");
234+
var createdCharacter = await _characterService.CreateCharacterAsync(createCommand);
235+
236+
createdCharacter.Should().NotBeNull();
237+
createdCharacter.Name.Should().Be("Lifecycle Character");
238+
239+
// Exists check
240+
var existsAfterCreate = await _characterService.CharacterExistsAsync(createdCharacter.Id);
241+
existsAfterCreate.Should().BeTrue();
242+
243+
// Update
244+
var updateCommand = TestDataBuilder.CreateUpdateCharacterCommand("Updated Lifecycle Character");
245+
var updatedCharacter = await _characterService.UpdateCharacterAsync(createdCharacter.Id, updateCommand);
246+
247+
updatedCharacter.Name.Should().Be("Updated Lifecycle Character");
248+
updatedCharacter.Id.Should().Be(createdCharacter.Id);
249+
250+
// Retrieve after update
251+
var retrievedAfterUpdate = await _characterService.GetCharacterByIdAsync(createdCharacter.Id);
252+
retrievedAfterUpdate.Name.Should().Be("Updated Lifecycle Character");
253+
254+
// Delete
255+
await _characterService.DeleteCharacterAsync(createdCharacter.Id);
256+
257+
// Verify deletion
258+
var existsAfterDelete = await _characterService.CharacterExistsAsync(createdCharacter.Id);
259+
existsAfterDelete.Should().BeFalse();
260+
261+
// Should throw when trying to retrieve deleted character
262+
await Assert.ThrowsAsync<NotFoundException>(
263+
() => _characterService.GetCharacterByIdAsync(createdCharacter.Id));
264+
}
265+
266+
[Fact]
267+
public async Task CreateCharactersWithSameName_ShouldAllowDuplicateNames()
268+
{
269+
// Arrange
270+
await _fixture.ClearDatabaseAsync();
271+
var sameName = "Duplicate Name Character";
272+
273+
// Act - Create multiple characters with the same name
274+
var character1 = await _characterService.CreateCharacterAsync(
275+
TestDataBuilder.CreateCreateCharacterCommand(sameName, "Description 1"));
276+
var character2 = await _characterService.CreateCharacterAsync(
277+
TestDataBuilder.CreateCreateCharacterCommand(sameName, "Description 2"));
278+
279+
// Assert
280+
character1.Should().NotBeNull();
281+
character2.Should().NotBeNull();
282+
character1.Id.Should().NotBe(character2.Id);
283+
character1.Name.Should().Be(sameName);
284+
character2.Name.Should().Be(sameName);
285+
character1.Description.Should().Be("Description 1");
286+
character2.Description.Should().Be("Description 2");
287+
288+
var allCharacters = await _characterService.GetAllCharactersAsync();
289+
allCharacters.Should().HaveCount(2);
290+
allCharacters.Should().OnlyContain(c => c.Name == sameName);
291+
}
292+
293+
#endregion
294+
295+
#region Edge Cases Integration Tests
296+
297+
[Fact]
298+
public async Task GetAllCharactersAsync_WithEmptyDatabase_ShouldReturnEmptyCollection()
299+
{
300+
// Arrange
301+
await _fixture.ClearDatabaseAsync();
302+
303+
// Act
304+
var characters = await _characterService.GetAllCharactersAsync();
305+
306+
// Assert
307+
characters.Should().NotBeNull();
308+
characters.Should().BeEmpty();
309+
}
310+
311+
[Fact]
312+
public async Task CreateCharacterWithSpecialCharacters_ShouldPersistCorrectly()
313+
{
314+
// Arrange
315+
await _fixture.ClearDatabaseAsync();
316+
var specialName = "特殊文字キャラクター!@#$%^&*()_+-=[]{}|;':\",./<>?";
317+
var specialDescription = "Éñgłīšh àñd 中文 ànd العربية ànd עברית ànd русский";
318+
319+
var createCommand = TestDataBuilder.CreateCreateCharacterCommand(
320+
specialName,
321+
specialDescription,
322+
"Special Role");
323+
324+
// Act
325+
var createdCharacter = await _characterService.CreateCharacterAsync(createCommand);
326+
var retrievedCharacter = await _characterService.GetCharacterByIdAsync(createdCharacter.Id);
327+
328+
// Assert
329+
retrievedCharacter.Name.Should().Be(specialName);
330+
retrievedCharacter.Description.Should().Be(specialDescription);
331+
}
332+
333+
#endregion
334+
}
335+
}

0 commit comments

Comments
 (0)