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
9️⃣ One-Paragraph Interview Answer
"In ASP.NET Core, we use FluentAssertions for readable and expressive assertions, AutoFixture to reduce test data boilerplate, and Moq to isolate dependencies in unit tests. Unit tests verify business logic in isolation, while integration tests use WebApplicationFactory and HttpClient to test the full request pipeline, often with an in-memory database. Together, they provide fast feedback and confidence in real-world behavior."
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