Roadmap › 1. .NET › Step 26
CC

Clean Code, Testing & Best Practices

Naming, functions, error handling, code smells and refactoring, unit testing with xUnit and Moq, TDD, code review, Git workflow, security and logging best practices for .NET teams.
What it is & where it is used

Clean code is code that other people can read, change and trust. Interviews for mid and senior roles check whether you write maintainable code, test it, review others' code and follow team practices (Git flow, CI, logging, security).

Core ideas, from Robert C. Martin's Clean Code (2008), Martin Fowler's Refactoring (1999, 2nd ed. 2018) and Kent Beck's Test-Driven Development (2002):

  • Code is read far more often than it is written — optimise for the reader.
  • Small, focused functions and classes with intention-revealing names.
  • Tests are part of the code, not an afterthought.
  • Leave the code cleaner than you found it (the "Boy Scout rule").
Versions & history
YearMilestone
1999Fowler, Refactoring (code smells catalogue); Beck, Extreme Programming Explained
2002Beck, Test-Driven Development: By Example
2004Feathers, Working Effectively with Legacy Code
2007xUnit.net 1.0 released (by NUnit's original author)
2008Martin, Clean Code
2011Martin, The Clean Coder
2018Refactoring 2nd edition
2024xUnit v3 released; MSTest 3.x, NUnit 4 are current

.NET analyzers: Roslyn analyzers ship in the SDK (<AnalysisLevel>latest</AnalysisLevel>), plus .editorconfig rules enforced at build.

Lifecycle

Code lifecycle in a team (typical Git + PR flow):

  1. Pick a ticket (Azure Boards/Jira) → create a branch feature/1234-order-export.
  2. Write a failing test (TDD) or write the code, then the tests.
  3. Run the analyzers, formatter (dotnet format) and tests locally.
  4. Commit small, meaningful commits; push; open a pull request.
  5. CI pipeline: build → unit tests → code coverage → static analysis (SonarQube) → security scan.
  6. Code review by 1–2 peers; address comments.
  7. Merge (squash) to main; CD deploys to dev → QA → staging → production.
  8. Monitor logs and metrics; fix bugs with a regression test first.

Test lifecycle (xUnit): for each test, a new instance of the test class is created (constructor = setup), the test runs, then Dispose() = teardown. Shared expensive setup uses IClassFixture<T> (per class) or collection fixtures (across classes).

Tools used to develop
AreaTools
Unit testingxUnit, NUnit, MSTest
MockingMoq, NSubstitute, FakeItEasy
AssertionsShouldly, FluentAssertions (v8+ needs a commercial licence)
Integration testsWebApplicationFactory (Microsoft.AspNetCore.Mvc.Testing), Testcontainers, Respawn
CoverageCoverlet, ReportGenerator, Visual Studio Enterprise
Static analysisRoslyn analyzers, SonarQube/SonarCloud, ReSharper, StyleCop.Analyzers
Formattingdotnet format, .editorconfig, CSharpier
Mutation testingStryker.NET
Architecture testsNetArchTest, ArchUnitNET
SecurityDependabot, dotnet list package --vulnerable, GitHub Advanced Security, OWASP ZAP