Files
Amaury Levé 948a9a52ef Add exp-mock-usage-analysis skill and evaluation (#483)
* Add exp-mock-usage-analysis skill and evaluation

New experimental skill that detects unused, redundant, or unnecessary
mocks in .NET test suites. Covers Moq, NSubstitute, FakeItEasy, and
manual test doubles.

- SKILL.md with 6-step workflow: gather code, classify mocks, detect
  anti-patterns, incorporate runtime data, generate recommendations,
  report findings
- eval.yaml with 10 scenarios: trivial type mocking, unused setups,
  redundant configs, stable utility mocks, well-placed mocks (no false
  positives), NSubstitute support, FakeItEasy support, setup sprawl,
  and 2 non-activation boundary tests
- Fixture files for each scenario with production + test code
- CODEOWNERS entry for @dotnet/dotnet-testing

* Remove no-headroom scenarios, increase NSubstitute timeout

Remove 4 scenarios where baseline already scores 5.0/5 (model handles
these well without skill guidance):
- Detect mocking of DTOs, records, and enums
- Recognize well-placed mocks without inventing false positives
- Decline when asked about non-mock test anti-patterns
- Decline mock framework migration request

Increase NSubstitute scenario timeout from 120s to 180s to avoid
baseline timeouts impacting scoring.

Remaining 6 scenarios all show positive skill impact (3→5, 3→4, etc).

* Document areas the model handles well without the skill

Add a subsection under 'When Not to Use' listing mock-related tasks
where the base model already scores 5.0/5 without skill guidance:
- Mocking trivial types (DTOs, records, enums)
- Recognizing well-placed mocks (no false positives)

* Fix md

* Improve
2026-04-02 10:03:17 +00:00

57 lines
1.7 KiB
C#

namespace InventorySystem;
public interface IInventoryRepository
{
int GetStock(string productId);
void UpdateStock(string productId, int quantity);
IReadOnlyList<string> GetLowStockProducts(int threshold);
}
public interface IAuditLogger
{
void LogStockChange(string productId, int oldQuantity, int newQuantity, string reason);
}
public interface IEventBus
{
void Publish(string eventName, object payload);
}
public class InventoryService
{
private readonly IInventoryRepository _repository;
private readonly IAuditLogger _auditLogger;
private readonly IEventBus _eventBus;
public InventoryService(IInventoryRepository repository, IAuditLogger auditLogger, IEventBus eventBus)
{
_repository = repository;
_auditLogger = auditLogger;
_eventBus = eventBus;
}
public bool Reserve(string productId, int quantity)
{
var current = _repository.GetStock(productId);
if (current < quantity)
return false;
var newQty = current - quantity;
_repository.UpdateStock(productId, newQty);
_auditLogger.LogStockChange(productId, current, newQty, "Reserved");
_eventBus.Publish("StockReserved", new { productId, quantity, remaining = newQty });
return true;
}
public void Restock(string productId, int quantity)
{
if (quantity <= 0)
throw new ArgumentOutOfRangeException(nameof(quantity));
var current = _repository.GetStock(productId);
var newQty = current + quantity;
_repository.UpdateStock(productId, newQty);
_auditLogger.LogStockChange(productId, current, newQty, "Restocked");
}
}