TestHarness.Analyzers
0.1.0-1
dotnet add package TestHarness.Analyzers --version 0.1.0-1
NuGet\Install-Package TestHarness.Analyzers -Version 0.1.0-1
<PackageReference Include="TestHarness.Analyzers" Version="0.1.0-1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="TestHarness.Analyzers" Version="0.1.0-1" />
<PackageReference Include="TestHarness.Analyzers"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add TestHarness.Analyzers --version 0.1.0-1
#r "nuget: TestHarness.Analyzers, 0.1.0-1"
#:package TestHarness.Analyzers@0.1.0-1
#addin nuget:?package=TestHarness.Analyzers&version=0.1.0-1&prerelease
#tool nuget:?package=TestHarness.Analyzers&version=0.1.0-1&prerelease
TestHarness.Analyzers
A Roslyn analyzer library that detects code patterns blocking "seams" in legacy code, based on Michael Feathers' Working Effectively with Legacy Code.
What are Seams?
A seam is a place where you can alter behavior in your program without editing in that place. Seams are essential for testing because they allow you to substitute dependencies, mock behaviors, and isolate code under test.
This analyzer identifies 18 anti-patterns (SEAM001-SEAM018) across 5 categories that hinder testability by blocking seams.
Installation
dotnet add package TestHarness.Analyzers
Or via Package Manager:
Install-Package TestHarness.Analyzers
Diagnostic Rules
Direct Dependencies
| Rule | Description |
|---|---|
| SEAM001 | Direct instantiation of concrete types |
| SEAM002 | Concrete type parameters without abstraction |
| SEAM003 | Factory method returns concrete type |
Static Dependencies
| Rule | Description |
|---|---|
| SEAM004 | Static method calls |
| SEAM005 | Static property access |
| SEAM006 | Extension method dependency |
| SEAM007 | Static event subscription |
| SEAM008 | Ambient context usage |
Inheritance Blockers
| Rule | Description |
|---|---|
| SEAM009 | Sealed class prevents inheritance |
| SEAM010 | Non-virtual method prevents override |
| SEAM011 | Private method contains logic |
Global State
| Rule | Description |
|---|---|
| SEAM012 | Singleton pattern usage |
| SEAM013 | Static mutable field |
| SEAM014 | Service locator pattern |
Infrastructure Dependencies
| Rule | Description |
|---|---|
| SEAM015 | Direct file system access |
| SEAM016 | Direct HTTP client usage |
| SEAM017 | Direct database access |
| SEAM018 | Direct process invocation |
Configuration
Suppress diagnostics or exclude specific types via .editorconfig:
# Disable a rule entirely
dotnet_diagnostic.SEAM001.severity = none
# Exclude specific types from SEAM001
dotnet_code_quality.SEAM001.excluded_types = T:MyNamespace.AllowedFactory
# Exclude specific methods from SEAM004
dotnet_code_quality.SEAM004.excluded_methods = M:System.Console.WriteLine
Example
public class OrderService
{
// SEAM001: Direct instantiation creates hard dependency
private readonly EmailService _emailService = new EmailService();
// Better: Inject the dependency
private readonly IEmailService _emailService;
public OrderService(IEmailService emailService)
{
_emailService = emailService;
}
}
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Acknowledgments
This project is inspired by Michael Feathers' book Working Effectively with Legacy Code. The concept of "seams" as places where you can alter program behavior without editing in that place comes directly from his work. Thank you to Michael Feathers for providing such valuable insights into making legacy code testable.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 0.1.0-1 | 71 | 1/16/2026 |