Dreamine.FullKit.Tests 1.0.0.0
Dreamine.FullKit.Tests 기능을 검증하는 자동화 테스트 프로젝트입니다.
로딩중...
검색중...
일치하는것 없음
DreamineContainerTests.cs
이 파일의 문서화 페이지로 가기
1using Dreamine.MVVM.Core.DependencyInjection;
2using Dreamine.MVVM.Core;
3
5
6// All classes in this file modify the DMContainer static facade.
7// Placing them in the same xUnit Collection serializes their execution
8// and prevents cross-class state leakage.
17[CollectionDefinition(Name)]
18public sealed class DMContainerCollection : ICollectionFixture<DMContainerFixture>
19{
28 public const string Name = "DMContainer";
29}
30
39public sealed class DMContainerFixture : IDisposable
40{
49 public DMContainerFixture() => DMContainer.Reset();
58 public void Dispose() => DMContainer.Reset();
59}
60
69[Collection(DMContainerCollection.Name)]
71{
80 [Fact]
82 {
83 DMContainer.Reset();
84 Assert.False(DMContainer.IsRegistered<IDisposable>());
85 }
86
95 [Fact]
97 {
98 DMContainer.Reset();
99 DMContainer.Register<DMContainerFixture>();
100
101 var resolver = DMContainer.GetResolver();
102 var instance = resolver.Resolve<DMContainerFixture>();
103
104 Assert.NotNull(instance);
105 }
106
115 [Fact]
117 {
118 DMContainer.Reset();
119 var resolver = DMContainer.GetResolver();
120 var found = resolver.TryResolve<IDisposable>(out var result);
121
122 Assert.False(found);
123 Assert.Null(result);
124 }
125}
126
135[Collection(DMContainerCollection.Name)]
136public sealed class DreamineContainerTests
137{
146 [Fact]
148 {
149 var container = new DreamineContainer();
150 container.Register<IClock, FixedClock>();
151 container.Register<ReportService>();
152
153 var first = container.Resolve<ReportService>();
154 var second = container.Resolve<ReportService>();
155
156 Assert.NotSame(first, second);
157 Assert.IsType<FixedClock>(first.Clock);
158 Assert.Equal("2026-06-07", first.CreateReportName());
159 }
160
169 [Fact]
171 {
172 var container = new DreamineContainer();
173 container.RegisterSingleton<IClock, FixedClock>();
174
175 var first = container.Resolve<IClock>();
176 var second = container.Resolve<IClock>();
177
178 Assert.Same(first, second);
179 }
180
189 [Fact]
191 {
192 var container = new DreamineContainer();
193
194 var instance = container.Resolve<FixedClock>();
195
196 Assert.Equal(new DateOnly(2026, 6, 7), instance.Today);
197 }
198
207 [Fact]
209 {
210 var container = new DreamineContainer();
211
212 var exception = Assert.Throws<InvalidOperationException>(
213 () => container.Resolve<IClock>());
214
215 Assert.Contains("is not registered", exception.Message);
216 }
217
226 [Fact]
228 {
229 var container = new DreamineContainer();
230 container.Register<CircularA>();
231 container.Register<CircularB>();
232
233 var exception = Assert.Throws<InvalidOperationException>(
234 () => container.Resolve<CircularA>());
235
236 Assert.Contains("Circular dependency", exception.Message);
237 }
238
255 [Fact]
257 {
259
260 var container = new DreamineContainer();
261 container.RegisterSingleton<SlowSingleton>();
262
263 var tasks = Enumerable.Range(0, 32)
264 .Select(_ => Task.Run(() => container.Resolve<SlowSingleton>()))
265 .ToArray();
266
267 var instances = await Task.WhenAll(tasks);
268
269 Assert.Single(instances.Distinct());
270 Assert.Equal(1, SlowSingleton.CreatedCount);
271 }
272
289 [Fact]
291 {
292 var container = new DreamineContainer();
293 container.Register<IndependentA>();
294 container.Register<IndependentB>();
295
296 var tasks = Enumerable.Range(0, 16)
297 .Select(index => Task.Run<object>(() =>
298 index % 2 == 0
299 ? container.Resolve<IndependentA>()
300 : container.Resolve<IndependentB>()))
301 .ToArray();
302
303 var instances = await Task.WhenAll(tasks);
304
305 Assert.Equal(16, instances.Length);
306 Assert.All(instances, Assert.NotNull);
307 }
308
317 [Fact]
319 {
320 var container = new DreamineContainer();
321 container.RegisterSingleton<IClock, FixedClock>();
322
323 _ = container.Resolve<IClock>();
324
325 container.Register<IClock, AlternateClock>();
326
327 var resolved = container.Resolve<IClock>();
328
329 Assert.IsType<AlternateClock>(resolved);
330 }
331
340 [Fact]
342 {
343 DMContainer.Reset();
344
345 // The no-registry overload scans the given assembly and registers into DMContainer directly.
346 Dreamine.MVVM.Core.DreamineAutoRegistrar.RegisterAll(typeof(DreamineContainerTests).Assembly);
347
348 // AutoRegistrationViewModel matches the naming convention filter used by DreamineAutoRegistrar.
349 Assert.True(DMContainer.IsRegistered<AutoRegistrationViewModel>());
350 }
351
360 [Fact]
362 {
363 DMContainer.Reset();
364 DMContainer.Register<IClock, FixedClock>();
365
366 Assert.True(DMContainer.IsRegistered<IClock>());
367
368 DMContainer.Reset();
369
370 Assert.False(DMContainer.IsRegistered<IClock>());
371 }
372
381 [Fact]
383 {
384 var container = new DreamineContainer();
385 var disposable = new DisposableSingleton();
386 container.RegisterSingleton<DisposableSingleton>(disposable);
387
388 _ = container.Resolve<DisposableSingleton>();
389 Assert.False(disposable.IsDisposed);
390
391 container.Dispose();
392
393 Assert.True(disposable.IsDisposed);
394 }
395
404 [Fact]
406 {
407 var container = new DreamineContainer();
408 var disposable = new DisposableSingleton();
409 container.RegisterSingleton<DisposableSingleton>(disposable);
410
411 container.Dispose();
412 container.Dispose();
413
414 Assert.Equal(1, disposable.DisposeCount);
415 }
416
425 [Fact]
427 {
428 DMContainer.Reset();
429 var disposable = new DisposableSingleton();
430 DMContainer.RegisterSingleton(disposable);
431
432 _ = DMContainer.Resolve<DisposableSingleton>();
433 Assert.False(disposable.IsDisposed);
434
435 DMContainer.Reset();
436
437 Assert.True(disposable.IsDisposed);
438 }
439
448 private interface IClock
449 {
458 DateOnly Today { get; }
459 }
460
469 private sealed class FixedClock : IClock
470 {
479 public DateOnly Today { get; } = new(2026, 6, 7);
480 }
481
490 private sealed class AlternateClock : IClock
491 {
500 public DateOnly Today { get; } = new(2026, 6, 8);
501 }
502
511 private sealed class SlowSingleton
512 {
521 private static int _createdCount;
522
532 {
533 Thread.Sleep(20);
534 Interlocked.Increment(ref _createdCount);
535 }
536
545 public static int CreatedCount => Volatile.Read(ref _createdCount);
546
555 public static void Reset()
556 {
557 Volatile.Write(ref _createdCount, 0);
558 }
559 }
560
569 private sealed class IndependentA
570 {
571 }
572
581 private sealed class IndependentB
582 {
583 }
584
593 private sealed class ReportService
594 {
611 public ReportService(IClock clock)
612 {
613 Clock = clock;
614 }
615
624 public IClock Clock { get; }
625
642 public string CreateReportName()
643 {
644 return Clock.Today.ToString("yyyy-MM-dd");
645 }
646 }
647
656 private sealed class CircularA
657 {
674 public CircularA(CircularB dependency)
675 {
676 Dependency = dependency;
677 }
678
687 public CircularB Dependency { get; }
688 }
689
698 private sealed class CircularB
699 {
716 public CircularB(CircularA dependency)
717 {
718 Dependency = dependency;
719 }
720
729 public CircularA Dependency { get; }
730 }
731
732 // Matches the ViewModel naming convention used by NamingConventionAutoRegistrationFilter.
741 public sealed class AutoRegistrationViewModel { }
742
751 private sealed class DisposableSingleton : IDisposable
752 {
761 private int _disposeCount;
762
771 public bool IsDisposed => Volatile.Read(ref _disposeCount) > 0;
780 public int DisposeCount => Volatile.Read(ref _disposeCount);
781
790 public void Dispose() => Interlocked.Increment(ref _disposeCount);
791 }
792}