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
Personautomatically
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 Test | Integration Test |
|---|---|
| Fast | Slower |
| Isolated | Real pipeline |
| Mock dependencies | Real DI |
| Test logic | Test flow |
Integration Tests in ASP.NET Core
What They Test
- Routing
- Model binding
- Controllers + Services
- Views / API responses
- DB interaction
Tools Used
| Tool | Purpose |
|---|---|
| WebApplicationFactory | Test server |
| HttpClient | Send requests |
| InMemory DB | Isolated DB |
| FluentAssertions | Assertions |
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
- FluentAssertions = readable assertions
- AutoFixture = auto test data
- Moq = isolate dependencies
- Unit tests = logic
- Integration tests = flow
- WebApplicationFactory = real app in tests