Moq用例集合

唠叨

Moq是我最熟悉的Mocking框架,过去曾经短暂地切换到RhinoMocks。但总归还是回到Moq。倒不是因为觉得Moq能比RhinoMock要好多少,主要还是因为熟悉。用了Moq这么些年头,今天才决定开始写篇文章,讲讲Moq的一些具体使用方法。假设大家都有一定.Net的基础,所以在文章里我就不再多说编程的技巧。Generic programming和Lamda Expression是Moq框架使用最频繁的两个技术,如果哪位朋友想更多地了解这两个技术,MSDN上的文章《Generics (C# programming guide)》和《Lamda Expressions (C# programming guide)》是很好的切入点。一直坚定地认为代码是程序员交流的最好语言,以我个人的经验,要学习使用一个新的框架,与其阅读长篇大论,我更加倾向与在StackOverflow或是CSDN上找一段用例。所以在这篇文章里,我尽量多说代码少说话,希望这篇文章能成为大家收藏夹里的一篇有用的参考。

本文提到的所有的代码都在GitHub里了,有需要的朋友请随意下载 大笑

GitHub:https://github.com/gaogang/example.moq.git

言归正传

1. Setup

        [Test]
        public void RegisterPatient_RegisterAPatient_ShouldCallSavePatientOnRepository()
        {
            // Arrange
            var repository = new Mock<IPatientRepository>();
            var expected = "Test";

            // 检验:
            // 1. IPatientRepository的SavePatient函数会被调用
            // 2. SavePatient的入参和预期一致
            repository.Setup(r => r.SavePatient(It.Is<Patient>(p => p.PatientName == expected)))   
                .Verifiable();

            var target = new PatientRegistrationService(repository.Object);

            // Action
            target.RegisterPatient(expected);

            // Assert
            repository.Verify();
        }


2. Setup和Return

        <span style="font-weight: normal;">[Test]
        public void RegisterPatient_RegisterAPatient_ShouldReturnPatientId()
        {
            // Arrange
            var repository = new Mock<IPatientRepository>();
            var expected = 111111;

            repository.Setup(r => r.SavePatient(It.IsAny<Patient>()))
                // 模拟SavePatient函数的返回值
                .Returns(expected);

            var target = new PatientRegistrationService(repository.Object);

            // Action
            var actual = target.RegisterPatient("Anything");

            // Assert
            Assert.AreEqual(expected, actual, 
                "RegisterPatient应该返回IPatientRepository.SavePatient的返回值");
        }</span>

3. Setup和Callback

        [Test]
        public void RegisterPatients_RegisterMultiplaePatients_ShouldCallSaveOnRepositoryMultipleTimes()
        {
            // Arrange
            var repository = new Mock<IPatientRepository>();
            var expected = new Collection<string>
            {
                "A",
                "B",
                "C",
                "D"
            };

            var actual = new Collection<string>();

            repository.Setup(r => r.SavePatient(It.IsAny<Patient>()))
                // 在Callback函数里把SavePatient的入参添加到actual列表中
                .Callback<Patient>(p => actual.Add(p.PatientName));

            var target = new PatientRegistrationService(repository.Object);

            // Action
            target.RegisterPatients(expected);

            // Assert
            CollectionAssert.AreEqual(expected, actual,
                "期待集合和实际集合应该完全相符");
        }

4. Setup和CallBase



<pre name="code" class="csharp">        [Test]
        public void AddPatien_CreateNewPatientRecord_ShouldRegisterThePatientAndUpdatePatientList()
        {
            // Arrange
            var presenterMock = new Mock<PatientListPresenter>();
            var patient = "Test Patient";

            // CallBase设为真时,Moq允许局部替换
            presenterMock.CallBase = true;

            // 当PatientListPresenter的RegisterPatient函数被调用时,我们要验证AddPatient会:
            // 1. 调用RegisterPatient函数
            // 2. 调用UpdatePatientList函数
            presenterMock.Setup(p => p.RegisterPatient(It.Is<string>(n => n == patient))).Verifiable();
            presenterMock.Setup(p => p.UpdatePatientList()).Verifiable();

            // Action
            presenterMock.Object.AddPatient(patient); // CallBase设为真时
                                                      // 我们可以这样来直接调用AddPatient函数

            // Assert
            presenterMock.Verify();
        }


 

Setup属性

5. SetupGet

        [Test]
        public void Save_RegisterNewPatient_ShouldGetPatientNameFromView()
        {
            // Arrange
            var registrationService = new Mock<IPatientRegistrationService>();
            var view = new Mock<IPatientRegistrationFormView>();

            var patientName = "Test Patient";

            // 设置PatientName属性的Getter来返回测试用的病人姓名
            view.SetupGet(v => v.PatientName).Returns(patientName).Verifiable();

            // RegisterPatient用的病人姓名应该与PatientName属性的值一致
            registrationService.Setup(r => r.RegisterPatient(It.Is<string>(n => n == patientName)))
                .Verifiable();

            var presenter = new PatientRegistrationFormViewPresenter(view.Object, registrationService.Object);

            // Action
            presenter.Save();

            // Assert
            view.Verify();
            registrationService.Verify();
        }

6. SetupSet

        [Test]
        public void Load_LoadPatientInfo_ShouldSetPatientNameToView()
        {
            // Arrange
            var registrationService = new Mock<IPatientRegistrationService>();
            var view = new Mock<IPatientRegistrationFormView>();

            var patientName = "Test Patient";

            // 插入GetPatient的返回值
            registrationService.Setup(r => r.GetPatient()).Returns(patientName)
                .Verifiable();

            // 设置PatientName属性的Setter设置值应当与GetPatient返回值一致病人姓名
            view.SetupSet(v => v.PatientName = It.Is<string>(n => n == patientName))
                .Verifiable();

            var presenter = new PatientRegistrationFormViewPresenter(view.Object, registrationService.Object);

            // Action
            presenter.Load();

            // Assert
            view.Verify();
            registrationService.Verify();
        }


Verify

7. Verify目标函数的调用次数 

        [Test]
        public void RegisterPatient_RegisterAPatient_VerifyCallSavePatientOnRepository()
        {
            // Arrange
            var repository = new Mock<IPatientRepository>();
            var expected = "Test";

            var target = new PatientRegistrationService(repository.Object);

            // Action
            target.RegisterPatient(expected);

            // Assert
            // 检验:
            // 1. IPatientRepository的SavePatient函数会被调用
            // 2. SavePatient的入参和预期一致
            // 3. SavePatient只会被调用一次
            repository.Verify(r => r.SavePatient(It.Is<Patient>(p => p.PatientName == expected)), 
                Times.Once);
        }

8. VerifyGet

        [Test]
        public void Save_RegisterNewPatient_ShouldGetPatientNameFromView()
        {
            // Arrange
            var registrationService = new Mock<IPatientRegistrationService>();
            var view = new Mock<IPatientRegistrationFormView>();

            var presenter = new PatientRegistrationFormViewPresenter(view.Object, registrationService.Object);

            // Action
            presenter.Save();

            // Assert
            view.Verify(v => v.PatientName, Times.Once);
        }


9. VerifySet

        [Test]
        public void Load_LoadPatientInfo_ShouldSetPatientNameToView()
        {
            // Arrange
            var registrationService = new Mock<IPatientRegistrationService>();
            var view = new Mock<IPatientRegistrationFormView>();

            var patientName = "Test Patient";

            // 插入GetPatient的返回值
            registrationService.Setup(r => r.GetPatient()).Returns(patientName);

            var presenter = new PatientRegistrationFormViewPresenter(view.Object, registrationService.Object);

            // Action
            presenter.Load();

            // Assert
            view.Verify(v => v.PatientName == patientName, Times.Once);
        }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值