C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
99: Mocking with Moq
Why can't I just write a "Fake" class manually instead of using Moq?
You totally can. In the early days, we all did. You'd create a FakePaymentGateway : IPaymentGateway class, add some boolean flags to track if a method was called, and manually set return values. But here is the problem: as soon as you need a slightly different behavior for a second test—like making the payment fail instead of succeed—you either have to add more complex logic to your fake or create FakePaymentGatewaySuccess and FakePaymentGatewayFailure.
It becomes a maintenance nightmare. Moq lets you create these "fakes" on the fly inside your test method. Instead of writing a whole new class, you just tell Moq, "For this specific test, when this method is called with these arguments, return this value." It keeps your test project clean and your intent clear.
How do I actually tell a mock what to return?
The core of Moq is the Setup method. Think of it as programming the behavior of your dependency for a specific scenario. Let's say we have an OrderService that depends on an IPaymentGateway. We don't want to hit a real API and spend real money during a unit test, right?
// Setup the mock
var paymentMock = new Mock<IPaymentGateway>();
// Tell it: "Whenever ProcessPayment is called with any amount, return true"
paymentMock.Setup(p => p.ProcessPayment(It.IsAny<decimal>()))
.Returns(true);
// Inject the .Object (the actual generated instance) into your service
var service = new OrderService(paymentMock.Object);
var result = service.PlaceOrder(myOrder);
Assert.True(result.Success);
Notice It.IsAny<decimal>(). That's a Moq matcher. I'm telling Moq I don't care what the specific amount is for this test; I just want the payment to succeed regardless of the price.
How do I verify that a method was actually called?
Sometimes, a method doesn't return a value you can assert against. For example, if your OrderService calls an IEmailService to send a confirmation, the SendEmail method probably returns void. You can't check a return value, so you check the behavior.
This is where Verify comes in. It's essentially asking the mock, "Did this happen?"
var emailMock = new Mock<IEmailService>();
var service = new OrderService(paymentMock.Object, emailMock.Object);
service.PlaceOrder(myOrder);
// Verify that SendEmail was called exactly once with the customer's email
emailMock.Verify(e => e.SendEmail(myOrder.CustomerEmail, "Order Confirmed"), Times.Once);
I personally find Verify incredibly powerful for testing "side effects." If your code accidentally sends five emails to a customer because of a loop bug, Times.Once will catch that and fail the test immediately.
What happens if I forget to Setup a method?
By default, Moq uses "Loose" mocks. If you call a method that hasn't been set up, it won't throw an exception. Instead, it returns the default value for the return type—null for objects, false for booleans, and 0 for integers.
This is usually fine, but if you want your tests to fail the moment an unexpected call is made, you can set the MockBehavior.Strict option when creating the mock. I generally advise against Strict mocks unless you're dealing with a very fragile legacy system; they tend to make tests brittle because every single interaction must be explicitly defined, even the trivial ones.
📋 Practical Task
Exercise: Simulating a Payment Failure in the Order Processor
You are tasked with testing the error-handling logic of the OrderService. Your goal is to ensure that if the payment gateway fails, the order is marked as "Failed" and no confirmation email is sent to the customer.
Requirements:
- Create a mock for
IPaymentGatewayand setupProcessPaymentto returnfalse. - Create a mock for
IEmailService. - Call
OrderService.PlaceOrder(order). - Assert that the order status is
OrderStatus.Failed. - Use
Verifyto ensure thatIEmailService.SendEmailwas never called.
Starter Code Context:
public interface IPaymentGateway { bool ProcessPayment(decimal amount); }
public interface IEmailService { void SendEmail(string email, string message); }
public class Order { public string CustomerEmail { get; set; } public OrderStatus Status { get; set; } }
There are no comments for now.