** Simulate entitities **1. Verify with Parameter Matching:** ```csharp [Test] public async Task DeleteContact_ValidId_CallsRepository() { // ARRANGE var mockRepo = new Mock(); mockRepo.Setup(r => r.DeleteAsync(It.IsAny())) .ReturnsAsync(true); var service = new ContactService(mockRepo.Object); // ACT await service.DeleteContactAsync(5); // ASSERT - Verify called with specific parameter mockRepo.Verify(r => r.DeleteAsync(5), Times.Once); // Verify with predicate mockRepo.Verify(r => r.DeleteAsync(It.Is(id => id > 0)), Times.Once); } ``` **2. Callback - Capture Parameters:** ```csharp [Test] public async Task CreateContact_ValidData_SetsCorrectProperties() { // ARRANGE Contact capturedContact = null; var mockRepo = new Mock(); mockRepo.Setup(r => r.AddAsync(It.IsAny())) .Callback(c => capturedContact = c) // Capture the contact .ReturnsAsync((Contact c) => { c.Id = 1; return c; }); var service = new ContactService(mockRepo.Object); // ACT await service.CreateContactAsync("John", "Doe", "john@email.com", "555-1234"); // ASSERT - Verify captured values Assert.IsNotNull(capturedContact); Assert.AreEqual("John", capturedContact.FirstName); Assert.AreEqual("Doe", capturedContact.LastName); Assert.AreEqual("john@email.com", capturedContact.Email); } ``` **3. Sequential Setups:** ```csharp [Test] public async Task GetContactById_MultipleCallsReturnDifferentValues() { // ARRANGE var contact1 = new Contact { Id = 1, FirstName = "John" }; var contact2 = new Contact { Id = 2, FirstName = "Jane" }; var mockRepo = new Mock(); mockRepo.SetupSequence(r => r.GetByIdAsync(It.IsAny())) .ReturnsAsync(contact1) // First call .ReturnsAsync(contact2) // Second call .ReturnsAsync((Contact)null); // Third call var service = new ContactService(mockRepo.Object); // ACT var result1 = await service.GetContactByIdAsync(1); var result2 = await service.GetContactByIdAsync(2); var result3 = await service.GetContactByIdAsync(3); // ASSERT Assert.AreEqual("John", result1.FirstName); Assert.AreEqual("Jane", result2.FirstName); Assert.IsNull(result3); } ``` **4. Strict vs Loose Mocks:** ```csharp // LOOSE mock (default) - allows any method call var looseMock = new Mock(); // STRICT mock - throws exception for any non-setup method var strictMock = new Mock(MockBehavior.Strict); // This will throw because GetByIdAsync not setup strictMock.Object.GetByIdAsync(1); // Exception! // Use strict mocks to ensure only expected methods are called strictMock.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(contact); strictMock.Object.GetByIdAsync(1); // OK now ``` **5. Setup Exceptions:** ```csharp [Test] public void CreateContact_RepositoryThrows_PropagatesException() { // ARRANGE var mockRepo = new Mock(); mockRepo.Setup(r => r.EmailExistsAsync(It.IsAny())) .ThrowsAsync(new InvalidOperationException("Database error")); var service = new ContactService(mockRepo.Object); // ACT & ASSERT var ex = Assert.ThrowsAsync( async () => await service.CreateContactAsync("John", "Doe", "john@email.com", "555-1234") ); Assert.That(ex.Message, Does.Contain("Database error")); } ```