Vivek Kaushik
AboutBlogWorkMy Work Ethics
📘 C# / .NET Unit Testing

📘 C# / .NET Unit Testing

Created
Aug 23, 2024 04:26 AM
Tags

1️⃣ What is Unit Testing?

A unit test verifies a small, isolated piece of logic (usually a single method).
Goals:
  • Verify correctness
  • Prevent regressions
  • Enable refactoring
  • Document behavior
A true unit test:
  • Is isolated
  • Is fast
  • Has no external dependencies
  • Is deterministic

2️⃣ Testing Frameworks in .NET

Most common:
  • xUnit (modern, widely used)
  • NUnit
  • MSTest
👉 Modern ASP.NET Core projects typically use xUnit.

3️⃣ xUnit Basics

Install:
dotnet add package xunit dotnet add package xunit.runner.visualstudio dotnet add package Microsoft.NET.Test.Sdk

🔹 Basic Test Structure

public class CalculatorTests { [Fact] public void Add_ShouldReturnCorrectSum() { // Arrange var calculator = new Calculator(); // Act var result = calculator.Add(2, 3); // Assert Assert.Equal(5, result); } }

🔹 [Fact] vs [Theory]

[Fact]

Used for single test case.
[Fact] public void IsEven_ShouldReturnTrueForEvenNumbers()

[Theory]

Used for parameterized tests.
[Theory] [InlineData(2)] [InlineData(4)] public void IsEven_ShouldReturnTrue(int value) { var result = value % 2 == 0; Assert.True(result); }

4️⃣ Arrange – Act – Assert (AAA Pattern)

Every unit test should follow:
  1. Arrange → Setup test data
  1. Act → Execute logic
  1. Assert → Verify result
Example:
// Arrange var service = new OrderService(); // Act var result = service.CalculateTotal(100, 0.1); // Assert Assert.Equal(90, result);
Interviewers love seeing AAA clarity.

5️⃣ What is Mocking?

Mocking allows you to:
  • Replace real dependencies
  • Control behavior
  • Verify interactions
Common mocking library: Moq

6️⃣ Moq Basics

Install:
dotnet add package Moq

🔹 Example Scenario

Service:
public interface IEmailService { void Send(string message); } public class NotificationService { private readonly IEmailService _emailService; public NotificationService(IEmailService emailService) { _emailService = emailService; } public void Notify(string message) { _emailService.Send(message); } }

🔹 Mocking with Moq

[Fact] public void Notify_ShouldCallEmailService() { // Arrange var mockEmail = new Mock<IEmailService>(); var service = new NotificationService(mockEmail.Object); // Act service.Notify("Hello"); // Assert mockEmail.Verify(e => e.Send("Hello"), Times.Once); }
Key concepts:
  • Mock<T>
  • .Object
  • Verify
  • Times.Once

7️⃣ Setup Behavior

mockEmail .Setup(e => e.Send(It.IsAny<string>())) .Verifiable();
You can also return values:
mockRepo .Setup(r => r.GetById(1)) .Returns(new User { Id = 1 });

8️⃣ Testing Exceptions

[Fact] public void Divide_ByZero_ShouldThrowException() { var calculator = new Calculator(); Assert.Throws<DivideByZeroException>(() => calculator.Divide(10, 0)); }

9️⃣ Testing Async Methods

[Fact] public async Task GetUser_ShouldReturnUser() { var mockRepo = new Mock<IUserRepository>(); mockRepo.Setup(r => r.GetUserAsync(1)) .ReturnsAsync(new User { Id = 1 }); var service = new UserService(mockRepo.Object); var result = await service.GetUserAsync(1); Assert.NotNull(result); }
Important:
  • Use async Task
  • Use ReturnsAsync
  • Never use .Result in tests

🔟 Testing ASP.NET Core Controllers

Example:
[Fact] public void GetUser_ShouldReturnOk() { var mockService = new Mock<IUserService>(); mockService.Setup(s => s.GetUser(1)) .Returns(new User()); var controller = new UsersController(mockService.Object); var result = controller.GetUser(1); Assert.IsType<OkObjectResult>(result); }

1️⃣1️⃣ Test Naming Best Practices

Good naming format:
MethodName_Scenario_ExpectedResult
Example:
CalculateTotal_WithDiscount_ReturnsDiscountedValue
This shows clarity.

1️⃣2️⃣ Unit Test Best Practices

✅ Keep Tests Independent

No shared state.

✅ One Assert Conceptually

Test one behavior.

✅ Avoid Testing Implementation Details

Test behavior, not private methods.

✅ Do NOT Mock What You Don’t Own

Mock interfaces you control.

✅ Avoid Over-Mocking

Mock only external dependencies.

✅ Tests Must Be Deterministic

No random data.
No time-based logic without abstraction.

1️⃣3️⃣ Common Interview Questions


❓ What is the difference between Mock and Stub?

  • Stub → returns predefined data
  • Mock → verifies interaction
Moq does both.

❓ What is Integration Testing?

Tests multiple components together.
Example:
  • Controller + Database

❓ What Should NOT Be Unit Tested?

  • Framework code
  • EF Core internals
  • Simple getters/setters
  • Third-party library behavior

❓ How Do You Test Private Methods?

You don’t.
Test via public behavior.

1️⃣4️⃣ Advanced Topics (Senior-Level)


🔹 Testing EF Core

Use:
UseInMemoryDatabase()
Or better:
  • Use SQLite in-memory for realistic behavior.

🔹 AutoFixture (Test Data Generation)

Helps generate objects automatically.

🔹 FluentAssertions

Cleaner assertions:
result.Should().Be(5);

🔹 Test Fixtures (xUnit)

For shared setup:
public class DatabaseFixture : IDisposable { public DbContext Context { get; } public DatabaseFixture() { // Setup } public void Dispose() { // Cleanup } }

1️⃣5️⃣ Code Coverage

Use:
dotnet test --collect:"XPlat Code Coverage"
Important:
  • 100% coverage does NOT mean good tests.
  • Focus on meaningful behavior coverage.

1️⃣6️⃣ Common Anti-Patterns

❌ Testing multiple behaviors in one test
❌ Using real DB in unit tests
❌ Asserting too many things
❌ Using Thread.Sleep()
❌ Not isolating dependencies

1️⃣7️⃣ What Interviewers Actually Look For

At mid-level:
  • Understand xUnit basics
  • Can write clean tests
  • Understand mocking
At senior-level:
  • Knows isolation vs integration
  • Understands DI in testing
  • Avoids over-mocking
  • Knows test maintainability
  • Understands tradeoffs

🎯 Strong Interview Answer Summary

In .NET, unit testing is commonly done using xUnit. Tests follow the Arrange-Act-Assert pattern and focus on isolated behavior. External dependencies are mocked using libraries like Moq. Good tests are deterministic, independent, and validate behavior rather than implementation details. For integration testing, components are tested together, often using in-memory databases or test servers.

🚀 Final Advice for You

For interviews:
Be ready to:
  • Write a test live
  • Mock a dependency
  • Test async code
  • Explain DI in testing
  • Discuss when to use integration tests
  • Identify bad tests
If you want, next I can create:
  • A “Live Coding Interview Testing Cheatsheet”
  • Real-world service testing example
  • ASP.NET Core integration testing guide
  • Advanced mocking scenarios (callbacks, sequences, etc.)
Your move.
Table of Contents
1️⃣ What is Unit Testing?2️⃣ Testing Frameworks in .NET3️⃣ xUnit Basics🔹 Basic Test Structure🔹 [Fact] vs [Theory][Fact][Theory]4️⃣ Arrange – Act – Assert (AAA Pattern)5️⃣ What is Mocking?6️⃣ Moq Basics🔹 Example Scenario🔹 Mocking with Moq7️⃣ Setup Behavior8️⃣ Testing Exceptions9️⃣ Testing Async Methods🔟 Testing ASP.NET Core Controllers1️⃣1️⃣ Test Naming Best Practices1️⃣2️⃣ Unit Test Best Practices✅ Keep Tests Independent✅ One Assert Conceptually✅ Avoid Testing Implementation Details✅ Do NOT Mock What You Don’t Own✅ Avoid Over-Mocking✅ Tests Must Be Deterministic1️⃣3️⃣ Common Interview Questions❓ What is the difference between Mock and Stub?❓ What is Integration Testing?❓ What Should NOT Be Unit Tested?❓ How Do You Test Private Methods?1️⃣4️⃣ Advanced Topics (Senior-Level)🔹 Testing EF Core🔹 AutoFixture (Test Data Generation)🔹 FluentAssertions🔹 Test Fixtures (xUnit)1️⃣5️⃣ Code Coverage1️⃣6️⃣ Common Anti-Patterns1️⃣7️⃣ What Interviewers Actually Look For🎯 Strong Interview Answer Summary🚀 Final Advice for You
Copyright 2026 Vivek Kaushik