【问题标题】:why MOQ framework overrides all virtual methods - c#为什么 MOQ 框架会覆盖所有虚拟方法 - c#
【发布时间】:2015-01-21 13:32:19
【问题描述】:

我是 C# 的 MOQ 新手。 这是我的代码:

   public class CustomerBase
    {
        private List<Customer> customers = new List<Customer>();
        public const int MAX_CUSTOMERS = 100;

        public int CustomerCount()
        {
            return customers.Count();
        }

        public void AddCustomer(string name, string email)
        {
            if (CustomerCount() >= MAX_CUSTOMERS)
            {
                return;
            }
            Customer cus = new Customer(name);
            customers.Add(cus);
            SendEmail(email);
        }

        public virtual void SendEmail(string email)
        {
            throw new NotImplementedException();
        }
    }

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestAddUser()
        {
            Mock<CustomerBase> m = new Mock<CustomerBase>();
            m.Setup(x => x.SendEmail("k")).Verifiable(); // bypass send email because email is server is not setup
            m.Object.AddCustomer("max", "k@g");
            Assert.AreEqual(1, m.Object.CustomerCount());
        }
  }

测试通过。一旦我将 CustomerCount 设为虚拟,测试就会失败,因为该方法开始返回零。 有谁知道为什么以及如何防止这种行为?


更新代码 - 使用内部程序集失败:

   [assembly: InternalsVisibleTo("UnitTestProject1")] // make the test assembly internal
namespace MoqSmple1
{
    public class CustomerBase
    {
        private List<Customer> customers = new List<Customer>();
        public const int MAX_CUSTOMERS = 100;

        internal virtual int CustomerCount()
        {
            return customers.Count();
        }

        public void AddCustomer(string name, string email)
        {
            if (CustomerCount() >= MAX_CUSTOMERS)
            {
                return;
            }
            Customer cus = new Customer(name);
            customers.Add(cus);
            SendEmail(email);
        }

        internal virtual void SendEmail(string email)
        {
            throw new NotImplementedException();
        }
    }
}

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestAddUser()
        {
            Mock<CustomerBase> m = new Mock<CustomerBase>();
            m.Setup(x => x.SendEmail("k")).Verifiable(); // bypass send email because email is server is not setup
            m.Object.AddCustomer("max", "k@g");
            m.CallBase = true;// keep the default behaviour of virtual methods except the ones skipped
            Assert.AreEqual(1, m.Object.CustomerCount());
        }
    }
}

更新 我想通了:

  • 我需要一个公钥
  • 我需要将方法设为内部受保护虚拟

【问题讨论】:

    标签: c#


    【解决方案1】:

    你想设置&lt;YourMock&gt;.CallBase = trueHere is a good article on CallBase

    简而言之,Moq 默认会为所有虚拟方法创建一个代理,并且将 CallBase 设置为 true 会保留默认实现,除非您明确要求代理。

    【讨论】:

    • 谢谢。如果我可以问一个后续问题;使用 MOQ 需要您将一些生产代码更改为公共虚拟。有什么技术可以避免这样做吗?
    • 您可以将它们更改为内部虚拟并使用 InternalsVisibleTo[TestAssembly]。但是,否则你必须使用更强大的东西(RhinoMocks)......这让我更经常地质疑设计......请记住这一点
    • 谢谢@Jutin。这是一个很好的建议。
    • 我尝试了使用单独的程序集作为内部的建议。这会导致测试失败。由于某些未知原因,它导致 MOQ 不覆盖我希望跳过的方法。
    • 你用过:msdn.microsoft.com/en-us/library/0tke9fxk.aspx?我已经多次使用这个没有失败......
    猜你喜欢
    • 1970-01-01
    • 2011-03-15
    • 2011-05-21
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 2014-01-05
    • 2018-11-16
    相关资源
    最近更新 更多