Skip to main content

Testing Stack

Think of testing in 3 layers:

Unit Tests
├─ FluentAssertions (expressive checks)
├─ Moq (isolate dependencies)
└─ AutoFixture (generate data)

Integration Tests
└─ WebApplicationFactory + HttpClient

Fluent Assertions (FA) — How You Assert​

What it is (interview one-liner)​

FluentAssertions makes test assertions readable and expressive, closer to natural language.

Why people love it​

  • Clear failure messages
  • Self-documenting tests
  • Less "mental translation" than Assert.Equal

Compare with xUnit Assert​

Assert.Equal(5, result);

vs

result.Should().Be(5);

The second one reads like English.


Core FluentAssertions You MUST Remember​

✅ Basic​

result.Should().Be(5);
result.Should().NotBe(10);
result.Should().BeTrue();
result.Should().BeNull();

✅ Collections​

list.Should().HaveCount(3);
list.Should().Contain("apple");
list.Should().BeEquivalentTo(new[] {1,2,3}); // order ignored

✅ Strings​

name.Should().StartWith("John");
name.Should().Contain("Middle");

✅ Exceptions ⭐​

Action act = () => method();
act.Should().Throw<ArgumentException>()
.WithMessage("Invalid operation");

📌 Interview line:

"FluentAssertions improves readability and produces better failure messages."


AutoFixture — How You Create Test Data​

What problem it solves​

"I don't want to manually create objects with 10 properties every test."

What it does​

  • Auto-creates objects
  • Fills properties with sensible values
  • Removes boilerplate

Typical usage with xUnit​

[Theory, AutoData]
public void CreatePerson_ValidInput(Person person)
{
person.Should().NotBeNull();
}

AutoFixture creates Person automatically


When AutoFixture shines​

  • Large DTOs
  • Nested objects
  • Parameterized tests

📌 Interview line:

"AutoFixture reduces test setup noise and encourages broader test coverage."


Mocking — How You Isolate Units​

Why mocking exists​

Unit tests should:

  • ❌ Not hit DB
  • ❌ Not call APIs
  • ❌ Not rely on infrastructure

Mock dependencies


Moq — How You Mock in .NET​

Typical Moq Flow (Memorize This)​

Create mock
→ Setup behavior
→ Inject mock
→ Verify interaction

Example​

var repoMock = new Mock<IPersonsRepository>();

repoMock.Setup(r => r.AddPerson(It.IsAny<Person>()))
.ReturnsAsync(person);

Inject:

var service = new PersonsService(repoMock.Object);

Verify:

repoMock.Verify(r => r.AddPerson(It.IsAny<Person>()), Times.Once);

📌 Interview line:

"Moq allows us to control dependency behavior and verify interactions."


What NOT to Mock ❌​

  • The class under test
  • Value objects
  • Simple logic

Mock boundaries, not internals.


Unit Tests vs Integration Tests (BIG INTERVIEW FAVORITE)​

Unit TestIntegration Test
FastSlower
IsolatedReal pipeline
Mock dependenciesReal DI
Test logicTest flow

Integration Tests in ASP.NET Core​

What They Test​

  • Routing
  • Model binding
  • Controllers + Services
  • Views / API responses
  • DB interaction

Tools Used​

ToolPurpose
WebApplicationFactoryTest server
HttpClientSend requests
InMemory DBIsolated DB
FluentAssertionsAssertions

CustomWebApplicationFactory ⭐​

public class CustomWebApplicationFactory
: WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Test");

builder.ConfigureServices(services =>
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseInMemoryDatabase("TestDb"));
});
}
}

📌 Why this matters:

It spins up the real app, but safely.


Integration Test Example​

HttpResponseMessage response = await _client.GetAsync("/Persons/Index");

response.Should().BeSuccessful();

string html = await response.Content.ReadAsStringAsync();
html.Should().Contain("<table");

📌 You're testing what the user actually gets.


When to Use What (Very Important)​

Use Unit Tests when:​

  • Testing business logic
  • Testing validation
  • Testing edge cases

Use Integration Tests when:​

  • Testing full request flow
  • Testing EF + DI + routing
  • Testing views / APIs

Best Practices (Memorize This List)​

✅ Use FluentAssertions for readability ✅ Use AutoFixture to reduce setup noise ✅ Mock external dependencies ✅ Prefer unit tests for logic ✅ Use integration tests for confidence ❌ Don't mock everything ❌ Don't over-verify implementation


If You Remember ONLY 6 Things​

  1. FluentAssertions = readable assertions
  2. AutoFixture = auto test data
  3. Moq = isolate dependencies
  4. Unit tests = logic
  5. Integration tests = flow
  6. WebApplicationFactory = real app in tests