Skip to content

Commit d4048d4

Browse files
committed
test: 토큰 지금 관련 테스트 코드 추가
1 parent c280132 commit d4048d4

File tree

4 files changed

+761
-32
lines changed

4 files changed

+761
-32
lines changed

ProjectVG.Tests/Application/Services/Chat/ChatServiceSimpleTests.cs

Lines changed: 183 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,54 +21,206 @@ public class ChatServiceSimpleTests
2121
private readonly Mock<IChatMetricsService> _mockMetricsService;
2222
private readonly Mock<IConversationService> _mockConversationService;
2323
private readonly Mock<ICharacterService> _mockCharacterService;
24+
private readonly Mock<IServiceScopeFactory> _mockScopeFactory;
25+
private readonly Mock<IServiceScope> _mockScope;
26+
private readonly Mock<IServiceProvider> _mockServiceProvider;
27+
private readonly Mock<ILogger<ChatService>> _mockLogger;
2428

2529
public ChatServiceSimpleTests()
2630
{
2731
_mockMetricsService = new Mock<IChatMetricsService>();
2832
_mockConversationService = new Mock<IConversationService>();
2933
_mockCharacterService = new Mock<ICharacterService>();
34+
_mockScopeFactory = new Mock<IServiceScopeFactory>();
35+
_mockScope = new Mock<IServiceScope>();
36+
_mockServiceProvider = new Mock<IServiceProvider>();
37+
_mockLogger = new Mock<ILogger<ChatService>>();
38+
39+
// Setup scope factory chain
40+
_mockScopeFactory.Setup(x => x.CreateScope()).Returns(_mockScope.Object);
41+
_mockScope.Setup(x => x.ServiceProvider).Returns(_mockServiceProvider.Object);
42+
}
43+
44+
#region Service Scope Management Tests
45+
46+
[Fact]
47+
public void ChatService_Constructor_WithServiceScopeFactory_ShouldAcceptDependency()
48+
{
49+
// Arrange & Act & Assert
50+
var act = () => CreateTestChatService();
51+
act.Should().NotThrow("IServiceScopeFactory should be a valid dependency for ChatService");
3052
}
3153

32-
[Fact(Skip = "ChatService has complex dependencies that cannot be easily mocked. Integration tests should be used instead.")]
33-
public void ChatService_Constructor_ShouldNotThrow()
54+
[Fact]
55+
public void ServiceScopeFactory_CreateScope_ShouldReturnValidScope()
3456
{
35-
// This test is skipped because ChatService depends on concrete classes without interfaces,
36-
// making it difficult to unit test. The service should be refactored to depend on interfaces.
57+
// Arrange
58+
var mockScope = new Mock<IServiceScope>();
59+
var mockServiceProvider = new Mock<IServiceProvider>();
60+
mockScope.Setup(x => x.ServiceProvider).Returns(mockServiceProvider.Object);
61+
62+
var mockScopeFactory = new Mock<IServiceScopeFactory>();
63+
mockScopeFactory.Setup(x => x.CreateScope()).Returns(mockScope.Object);
64+
65+
// Act
66+
var scope = mockScopeFactory.Object.CreateScope();
67+
68+
// Assert
69+
scope.Should().NotBeNull();
70+
scope.ServiceProvider.Should().NotBeNull();
71+
mockScopeFactory.Verify(x => x.CreateScope(), Times.Once);
3772
}
3873

39-
[Fact(Skip = "ChatService has complex dependencies that cannot be easily mocked. Integration tests should be used instead.")]
40-
public async Task EnqueueChatRequestAsync_WithValidCommand_ShouldCallMetricsService()
74+
[Fact]
75+
public void ServiceScope_ShouldImplementIDisposable()
4176
{
42-
// This test is skipped because ChatService depends on concrete classes without interfaces,
43-
// making it difficult to unit test. The service should be refactored to depend on interfaces.
44-
await Task.CompletedTask;
77+
// Arrange
78+
var mockScope = new Mock<IServiceScope>();
79+
80+
// Act & Assert
81+
mockScope.Object.Should().BeAssignableTo<IDisposable>("IServiceScope should be disposable for proper resource management");
4582
}
4683

47-
private ChatService? TryCreateChatService()
84+
[Fact]
85+
public void ServiceProvider_GetRequiredService_ShouldResolveServicesCorrectly()
4886
{
49-
try
50-
{
51-
// Create a minimal service collection with all required services
52-
var services = new ServiceCollection();
53-
54-
// Add required services with mocks
55-
services.AddSingleton(_mockMetricsService.Object);
56-
services.AddSingleton(_mockConversationService.Object);
57-
services.AddSingleton(_mockCharacterService.Object);
58-
59-
// Add logging
60-
services.AddLogging(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Warning));
61-
62-
// Note: Due to the complex dependency graph of ChatService with concrete classes,
63-
// we cannot easily mock all dependencies. This is a limitation of the current design.
64-
// For proper unit testing, the ChatService should depend on interfaces, not concrete classes.
65-
66-
return null; // Indicates that ChatService cannot be easily unit tested with its current design
67-
}
68-
catch
87+
// Arrange
88+
var mockChatSuccessHandler = new Mock<ChatSuccessHandler>();
89+
var mockChatResultProcessor = new Mock<ChatResultProcessor>();
90+
91+
_mockServiceProvider.Setup(x => x.GetRequiredService<ChatSuccessHandler>())
92+
.Returns(mockChatSuccessHandler.Object);
93+
_mockServiceProvider.Setup(x => x.GetRequiredService<ChatResultProcessor>())
94+
.Returns(mockChatResultProcessor.Object);
95+
96+
// Act
97+
var successHandler = _mockServiceProvider.Object.GetRequiredService<ChatSuccessHandler>();
98+
var resultProcessor = _mockServiceProvider.Object.GetRequiredService<ChatResultProcessor>();
99+
100+
// Assert
101+
successHandler.Should().NotBeNull();
102+
resultProcessor.Should().NotBeNull();
103+
successHandler.Should().BeSameAs(mockChatSuccessHandler.Object);
104+
resultProcessor.Should().BeSameAs(mockChatResultProcessor.Object);
105+
}
106+
107+
[Fact]
108+
public async Task ProcessChatRequestInternalAsync_ShouldCreateNewScopeForBackgroundTasks()
109+
{
110+
// This test verifies the concept of scope creation for background tasks
111+
// The actual method is private and complex, so we test the scope creation pattern
112+
113+
// Arrange
114+
var mockChatSuccessHandler = new Mock<ChatSuccessHandler>();
115+
var mockChatResultProcessor = new Mock<ChatResultProcessor>();
116+
117+
_mockServiceProvider.Setup(x => x.GetRequiredService<ChatSuccessHandler>())
118+
.Returns(mockChatSuccessHandler.Object);
119+
_mockServiceProvider.Setup(x => x.GetRequiredService<ChatResultProcessor>())
120+
.Returns(mockChatResultProcessor.Object);
121+
122+
// Act - Simulate the scope creation pattern used in ChatService
123+
using var scope = _mockScopeFactory.Object.CreateScope();
124+
var successHandler = scope.ServiceProvider.GetRequiredService<ChatSuccessHandler>();
125+
var resultProcessor = scope.ServiceProvider.GetRequiredService<ChatResultProcessor>();
126+
127+
// Assert
128+
_mockScopeFactory.Verify(x => x.CreateScope(), Times.Once);
129+
successHandler.Should().NotBeNull();
130+
resultProcessor.Should().NotBeNull();
131+
132+
// Verify both services come from the same scope
133+
_mockServiceProvider.Verify(x => x.GetRequiredService<ChatSuccessHandler>(), Times.Once);
134+
_mockServiceProvider.Verify(x => x.GetRequiredService<ChatResultProcessor>(), Times.Once);
135+
136+
await Task.CompletedTask; // To satisfy async context
137+
}
138+
139+
[Fact]
140+
public void UsingScope_ShouldDisposeProperlyAndPreventObjectDisposedException()
141+
{
142+
// Arrange
143+
var disposeCalled = false;
144+
_mockScope.Setup(x => x.Dispose()).Callback(() => disposeCalled = true);
145+
146+
// Act
147+
using (var scope = _mockScopeFactory.Object.CreateScope())
69148
{
70-
return null;
149+
scope.Should().NotBeNull();
150+
disposeCalled.Should().BeFalse("Scope should not be disposed while in using block");
71151
}
152+
153+
// Assert
154+
disposeCalled.Should().BeTrue("Scope should be disposed after using block");
155+
_mockScope.Verify(x => x.Dispose(), Times.Once);
156+
}
157+
158+
[Fact]
159+
public void ServiceScope_MultipleServiceResolution_ShouldUseSameProvider()
160+
{
161+
// This test verifies that multiple services resolved from the same scope
162+
// use the same service provider instance, preventing DbContext disposal issues
163+
164+
// Arrange
165+
var mockChatSuccessHandler = new Mock<ChatSuccessHandler>();
166+
var mockChatResultProcessor = new Mock<ChatResultProcessor>();
167+
168+
_mockServiceProvider.Setup(x => x.GetRequiredService<ChatSuccessHandler>())
169+
.Returns(mockChatSuccessHandler.Object);
170+
_mockServiceProvider.Setup(x => x.GetRequiredService<ChatResultProcessor>())
171+
.Returns(mockChatResultProcessor.Object);
172+
173+
// Act
174+
using var scope = _mockScopeFactory.Object.CreateScope();
175+
var provider1 = scope.ServiceProvider;
176+
var provider2 = scope.ServiceProvider;
177+
178+
var service1 = provider1.GetRequiredService<ChatSuccessHandler>();
179+
var service2 = provider2.GetRequiredService<ChatResultProcessor>();
180+
181+
// Assert
182+
provider1.Should().BeSameAs(provider2, "Same scope should always return same ServiceProvider");
183+
service1.Should().NotBeNull();
184+
service2.Should().NotBeNull();
185+
186+
// Both services should be resolved from the same provider instance
187+
_mockServiceProvider.Verify(x => x.GetRequiredService<ChatSuccessHandler>(), Times.Once);
188+
_mockServiceProvider.Verify(x => x.GetRequiredService<ChatResultProcessor>(), Times.Once);
72189
}
190+
191+
#endregion
192+
193+
#region Helper Methods
194+
195+
private ChatService CreateTestChatService()
196+
{
197+
// Create minimal mocks for all required dependencies
198+
var mockValidator = new Mock<ChatRequestValidator>();
199+
var mockMemoryPreprocessor = new Mock<MemoryContextPreprocessor>();
200+
var mockInputProcessor = new Mock<ICostTrackingDecorator<UserInputAnalysisProcessor>>();
201+
var mockActionProcessor = new Mock<UserInputActionProcessor>();
202+
var mockLLMProcessor = new Mock<ICostTrackingDecorator<ChatLLMProcessor>>();
203+
var mockTTSProcessor = new Mock<ICostTrackingDecorator<ChatTTSProcessor>>();
204+
var mockResultProcessor = new Mock<ChatResultProcessor>();
205+
var mockFailureHandler = new Mock<ChatFailureHandler>();
206+
207+
return new ChatService(
208+
_mockMetricsService.Object,
209+
_mockScopeFactory.Object,
210+
_mockLogger.Object,
211+
_mockConversationService.Object,
212+
_mockCharacterService.Object,
213+
mockValidator.Object,
214+
mockMemoryPreprocessor.Object,
215+
mockInputProcessor.Object,
216+
mockActionProcessor.Object,
217+
mockLLMProcessor.Object,
218+
mockTTSProcessor.Object,
219+
mockResultProcessor.Object,
220+
mockFailureHandler.Object
221+
);
222+
}
223+
224+
#endregion
73225
}
74226
}

0 commit comments

Comments
 (0)