Skip to content

Commit 76e0b4e

Browse files
committed
feat: Implement GenerateDomainServiceUnitTestsWithAITask class for automated unit test generation
1 parent a060e7a commit 76e0b4e

File tree

1 file changed

+42
-12
lines changed

1 file changed

+42
-12
lines changed

Modules/Intent.Modules.AI.UnitTests/Tasks/GenerateDomainServiceUnitTestsWithAITask.cs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,15 @@ 2. You may only create or update the test file
122122
Domain services:
123123
- Coordinate business logic that doesn't naturally fit within a single aggregate
124124
- Work with repositories to load and manipulate domain entities
125-
- May call methods on domain entities to maintain domain invariants
125+
- Call methods on domain entities to maintain domain invariants and modify their state
126126
- Should maintain transactional consistency through Unit of Work
127+
128+
**CRITICAL for Testing**: Domain services orchestrate behavior by calling entity methods. Your tests MUST verify:
129+
1. The service loaded the correct entities (repository interaction)
130+
2. The entities' STATE changed correctly after calling their methods (property/collection assertions)
131+
3. The changes will be persisted (SaveChangesAsync called if needed)
132+
133+
Verifying ONLY repository calls without inspecting entity state is an INCOMPLETE test.
127134
128135
## Test Coverage Requirements
129136
Generate tests that cover these scenarios (where applicable to the domain service operation):
@@ -134,7 +141,11 @@ Generate tests that cover these scenarios (where applicable to the domain servic
134141
* Boundary values for value objects (e.g., zero amounts, min/max dates)
135142
* Null or invalid input parameters
136143
* Entity state preconditions (e.g., entity must be in certain state before operation)
137-
5. **Entity State Changes**: Verify that entities are modified correctly through their methods
144+
5. **Entity State Changes (CRITICAL)**:
145+
* ALWAYS verify that domain entities' state was actually modified by inspecting their properties/collections after the operation
146+
* Use Callback to capture entities OR directly inspect the entity reference passed to the service
147+
* Example: After calling `service.RevalueAsset(...)`, assert that `asset.CurrentValuation == expectedValue`
148+
* Don't just verify repository methods were called - verify the entity's state changed correctly
138149
6. **Repository Interactions**: Verify correct repository method calls (Find, Add, Update, Remove)
139150
7. **Unit of Work**: Verify SaveChangesAsync is called when state changes occur
140151
@@ -292,24 +303,29 @@ public async Task RevalueAssetAsync_UpdatesAssetValuation_WhenClientAndAssetExis
292303
AppraiserName = "John Appraiser"
293304
};
294305
295-
// Create minimal test entity - only set what's needed
306+
// CRITICAL: Create test entity and ensure we can verify state changes
296307
var client = new Client { Id = clientId };
308+
var asset = new Asset { Id = assetId, CurrentValuation = 100000m };
309+
client.AddAsset(asset); // Set up initial state
297310
298311
_clientRepositoryMock
299312
.Setup(x => x.FindByIdAsync(clientId, It.IsAny<CancellationToken>()))
300313
.ReturnsAsync(client);
301314
302315
// Act
303-
await _sut.RevalueAssetAsync(clientId, assetId, newValuation);
316+
await _service.RevalueAssetAsync(clientId, assetId, newValuation);
304317
305-
// Assert - Verify repository was called and entity method was invoked
318+
// Assert - CRITICAL: Verify domain entity STATE was actually modified
306319
_clientRepositoryMock.Verify(
307320
x => x.FindByIdAsync(clientId, It.IsAny<CancellationToken>()),
308321
Times.Once);
309322
310-
// Note: If Client.UpdateAssetValuation modifies state, verify that state here
311-
// The Unit of Work will save changes, so no explicit SaveChanges verification needed
312-
// unless the domain service explicitly calls it
323+
// Verify the asset's valuation was updated through the client aggregate
324+
var updatedAsset = client.Assets.FirstOrDefault(a => a.Id == assetId);
325+
Assert.NotNull(updatedAsset);
326+
Assert.Equal(250000m, updatedAsset.CurrentValuation);
327+
Assert.Equal(newValuation.ValuationDate, updatedAsset.ValuationDate);
328+
Assert.Equal(newValuation.AppraiserName, updatedAsset.AppraiserName);
313329
}
314330
315331
[Fact]
@@ -401,9 +417,11 @@ public async Task TransferAssetAsync_TransfersAsset_WhenBothClientsExist()
401417
var toClientId = Guid.NewGuid();
402418
var assetId = Guid.NewGuid();
403419
420+
var asset = new Asset { Id = assetId, ClientId = fromClientId, Value = 500000m };
404421
var fromClient = new Client { Id = fromClientId, IsActive = true };
422+
fromClient.AddAsset(asset); // Establish ownership
423+
405424
var toClient = new Client { Id = toClientId, IsActive = true };
406-
var asset = new Asset { Id = assetId, ClientId = fromClientId };
407425
408426
_clientRepositoryMock
409427
.Setup(x => x.FindByIdAsync(fromClientId, It.IsAny<CancellationToken>()))
@@ -418,10 +436,17 @@ public async Task TransferAssetAsync_TransfersAsset_WhenBothClientsExist()
418436
.ReturnsAsync(asset);
419437
420438
// Act
421-
await _sut.TransferAssetAsync(fromClientId, toClientId, assetId);
439+
await _service.TransferAssetAsync(fromClientId, toClientId, assetId);
422440
423-
// Assert
441+
// Assert - Verify BOTH domain state changes AND repository interactions
442+
// CRITICAL: Verify the asset ownership actually changed
424443
Assert.Equal(toClientId, asset.ClientId);
444+
445+
// Verify asset was removed from source client and added to destination
446+
Assert.DoesNotContain(asset, fromClient.Assets);
447+
Assert.Contains(asset, toClient.Assets);
448+
449+
// Repository verifications (secondary to state assertions)
425450
_clientRepositoryMock.Verify(
426451
x => x.FindByIdAsync(fromClientId, It.IsAny<CancellationToken>()),
427452
Times.Once);
@@ -523,7 +548,12 @@ public async Task CalculateCommissionAsync_AppliesCap_ForHighValueTransaction()
523548
## Critical Domain Service Testing Reminders
524549
- **Mock ALL repositories**: Domain services should not touch real databases
525550
- **Focus on coordination logic**: Test how the service orchestrates between entities and repositories
526-
- **Verify entity method calls**: Use Callback to capture entities and verify their state changes
551+
- **ALWAYS verify domain entity state changes (HIGHEST PRIORITY)**:
552+
* Domain services coordinate behavior across aggregates by calling methods on domain entities
553+
* After the service executes, ALWAYS inspect the entity's properties/collections to verify state changed correctly
554+
* Example: If service calls `client.UpdateAssetValuation(...)`, assert `client.Assets[x].CurrentValuation == expectedValue`
555+
* Repository verification alone (e.g., `Verify(x => x.FindByIdAsync(...))`) is INSUFFICIENT - you must prove the entity's state changed
556+
* Use the entity reference returned from repository mock to inspect its final state in assertions
527557
- **Test business rule enforcement**: Ensure domain invariants are maintained
528558
- **Test all exception paths**: Domain services often have multiple failure scenarios
529559
- **Minimal test data**: Only set properties relevant to the specific test scenario

0 commit comments

Comments
 (0)