This episode covers code quality: unit testing with xUnit, mocking with Moq, integration testing with WebApplicationFactory, and static analysis with Roslyn analyzers and quality tooling such as dotnet format.

An untested application is a time bomb. The bigger the codebase, the more expensive it is to fix bugs that slip into production. Testing is the safety net that gives you the courage to change code without fearing you'll break something else.
In the .NET ecosystem, the testing ecosystem is very mature: xUnit for unit testing, Moq for mocking, and WebApplicationFactory for integration testing at the HTTP level.
Episode 10 teaches those three testing layers, plus static analysis and analyzers to maintain quality without waiting for bugs to happen.
xUnit is the most popular testing framework in .NET. The test project is created separately from the application code, following the tests structure convention:
dotnet new xunit -n Toko.Tests -o tests/Toko.Tests
dotnet add tests/Toko.Tests reference src/Toko.App
dotnet sln Toko.sln add tests/Toko.TestsThe dotnet add ... reference src/Toko.App command connects the test project to the application project under test. Without this reference, the tests can't see the code being tested.
xUnit has two styles: Fact for a single specific case, and Theory for testing many inputs with one test:
public class KalkulatorTests
{
[Fact]
public void Tambah_DuaAngka_ReturnsJumlah()
{
var hasil = Kalkulator.Tambah(2, 3);
Assert.Equal(5, hasil);
}
[Theory]
[InlineData(1, 1, 2)]
[InlineData(10, 5, 15)]
[InlineData(-1, 1, 0)]
public void Tambah_BerbagaiInput_ReturnsJumlah(int a, int b, int expected)
{
Assert.Equal(expected, Kalkulator.Tambah(a, b));
}
}Run all tests with:
dotnet testThe dotnet test command builds the test project and runs all tests, showing a summary of passes and failures. Descriptive test names like Tambah_DuaAngka_ReturnsJumlah become living documentation of behavior.
Unit tests must be fast and deterministic, so external dependencies like databases or APIs are mocked. Moq creates substitute objects whose behavior you can control:
public interface IRepository
{
Task<Produk> GetByIdAsync(int id);
}
[Fact]
public async Task GetProduk_ProdukDitemukan_ReturnsProduk()
{
var mockRepo = new Mock<IRepository>();
mockRepo.Setup(r => r.GetByIdAsync(1))
.ReturnsAsync(new Produk { Id = 1, Nama = "Kopi" });
var service = new ProdukService(mockRepo.Object);
var hasil = await service.GetProduk(1);
Assert.Equal("Kopi", hasil.Nama);
}mockRepo.Setup(r => r.GetByIdAsync(1)) determines the answer when the method is called. With a mock, you test ProdukService logic without ever touching a real database.
An integration test runs a real web application in-process and sends real HTTP requests. WebApplicationFactory provides an HttpClient connected to the application:
public class ProdukApiTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public ProdukApiTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetProduk_ReturnsOk()
{
var response = await _client.GetAsync("/api/produk/1");
response.EnsureSuccessStatusCode();
}
}This integration test proves that routing, dependency injection, and the HTTP pipeline work together. For the database in tests, swap the provider for SQLite or a test container.
Roslyn analyzers detect problematic patterns in code as you write, not at runtime. Some built-in SDK analyzers are enabled by default. Run the quality checks:
dotnet format
dotnet format --verify-no-changes
dotnet build -warnaserrorThe dotnet format command tidies code style according to configuration, while --verify-no-changes ensures the code is already clean — very useful in CI. For deeper analysis, tools like SonarQube combine analyzers, coverage, and duplication detection in the pipeline.
Key takeaways:
Fact and Theory is the foundation of .NET unit testing.WebApplicationFactory tests the full HTTP stack including DI and routing.dotnet test runs all tests and gives a summary.dotnet format keep quality from the start.In the next episode 11 we enter the web world: web API and HTTP client — the basics of ASP.NET Core Web API, controllers and routing, model binding, HttpClient with typed clients, and API versioning and standard error responses.