如何在Moq回调方法中使用模拟对象并验证其属性值?
问题描述
我正在模拟如下接口:
public interface IVirtualFile { string Contents { get; set; } // ... void SaveToDisk(); // ... }
用于测试以下类:
public class InformationHandler { // ... public void PrepareAndSaveSpecificInfo(IVirtualFile p_objSaveFile) { // ... p_objSaveFile.Contents = z_strBeginning; // ... p_objSaveFile.Contents = String.Concat(p_objSaveFile.Contents, z_strOtherInformation); // ... p_objSaveFile.Contents = String.Concat(p_objSaveFile.Contents, z_strEnd); p_objSaveFile.SaveToDisk(); } // ... }
测试代码如下:
[TestFixture] public class TestInformationHandler { private Mock<IVirtualFile> _mockVirtualFile { get; set; } [OneTimeSetUp] public void CreateMocks() { // ... _mockVirtualFile = new Mock<IVirtualFile>(); _mockVirtualFile.Setup(vf => vf.SaveToDisk()).Callback(() => CheckSavedData()); // ... } private void CheckSavedData() { // ... } [Test] public void Test_PrepareAndSaveSpecificInfo() { // ... PrepareAndSaveSpecificInfo(_mockVirtualFile); // ... } }
遇到两个问题:
- 希望在
CheckSavedData方法中通过Assert验证模拟对象的Contents属性,但不清楚如何获取该模拟对象; - 调试时设置
_mockVirtualFile.Object.Contents = "abcdef"后,属性仍返回null,模拟对象的属性不保留设置的值。
解决方案
1. 解决模拟属性不保留值的问题
Moq默认不会自动跟踪属性的get和set行为,需要显式配置属性的存储逻辑,有两种方式可选:
方式一:单独配置指定属性
只针对Contents属性开启值保留:
[OneTimeSetUp] public void CreateMocks() { _mockVirtualFile = new Mock<IVirtualFile>(); // 配置Contents属性允许get/set并保留值 _mockVirtualFile.SetupProperty(vf => vf.Contents); _mockVirtualFile.Setup(vf => vf.SaveToDisk()).Callback(() => CheckSavedData()); }
方式二:配置所有属性自动跟踪
如果接口有多个需要保留值的属性,可一次性开启所有属性的跟踪:
[OneTimeSetUp] public void CreateMocks() { _mockVirtualFile = new Mock<IVirtualFile>(); // 自动跟踪所有属性的get/set行为 _mockVirtualFile.SetupAllProperties(); _mockVirtualFile.Setup(vf => vf.SaveToDisk()).Callback(() => CheckSavedData()); }
2. 在CheckSavedData中验证Contents属性
由于_mockVirtualFile已经是测试类的私有属性,直接在CheckSavedData方法中使用即可,无需额外传入。同时要修正测试方法的参数错误:需要传入模拟对象的实例(_mockVirtualFile.Object),而非Mock本身。
修正后的完整测试代码:
[TestFixture] public class TestInformationHandler { private Mock<IVirtualFile> _mockVirtualFile { get; set; } // 替换为实际测试用的预期值 private string z_strBeginning = "Prefix: "; private string z_strOtherInformation = "Sample Content"; private string z_strEnd = " :Suffix"; [OneTimeSetUp] public void CreateMocks() { _mockVirtualFile = new Mock<IVirtualFile>(); _mockVirtualFile.SetupProperty(vf => vf.Contents); _mockVirtualFile.Setup(vf => vf.SaveToDisk()).Callback(() => CheckSavedData()); } private void CheckSavedData() { // 构建预期的拼接结果 string expectedContent = z_strBeginning + z_strOtherInformation + z_strEnd; // 验证Contents属性是否符合预期 Assert.That(_mockVirtualFile.Object.Contents, Is.EqualTo(expectedContent)); } [Test] public void Test_PrepareAndSaveSpecificInfo() { var handler = new InformationHandler(); // 传入模拟对象的实例,而非Mock本身 handler.PrepareAndSaveSpecificInfo(_mockVirtualFile.Object); // 可选:验证SaveToDisk方法是否被调用一次 _mockVirtualFile.Verify(vf => vf.SaveToDisk(), Times.Once); } }
内容的提问来源于stack exchange,提问作者Jean-David Lanz
相关产品推荐
相关产品推荐

