如何模拟非虚方法?

[TestMethod] public void TestMethod1() { var mock = new Mock(); mock.Setup(x => x.SendEmail()).Returns(true); var cus = new Customer(); var result = cus.AddCustomer(mock.Object); Assert.IsTrue(result); } public class Customer { public bool AddCustomer(EmailService emailService) { emailService.SendEmail(); Debug.WriteLine("new customer added"); return true; } } public class EmailService { public virtual bool SendEmail() { throw new Exception("send email failed cuz bla bla bla"); } } 

EmailService.SendEmail方法必须是虚拟的才能模拟它。 有没有办法模拟非虚拟方法?

Moq不能在类上模拟非虚方法。 要么使用其他模拟框架,例如Type mock Isolator ,它实际上将IL编组到您的程序EmailService ,或者在EmailService上放置一个接口并模拟它。

模拟非虚拟方法涉及使用低级分析器API。 目前我认为唯一可用的选择是:

  • TypeMock
  • JustMock

两者都是商业版,即使JustMock有精简版,嘲笑非虚拟方法也只有商业版。 正如评论中所指出的那样,微软研究中的一些东西来自Pex和Moles项目

必须使用虚拟方法进行模拟的替代方法是使用接口。 这样你就可以模拟出一个完整的依赖。

 public interface IEmailService { bool SendEmail(); // etc... } public class EmailService : IEmailService { //... } 

现在,您可以创建IEmailService接口的IEmailService以便模拟其任何方法。 当然,您必须在适当的情况下将包含EmailService对象的变量类型更改为IEmailService

使用pose 。 允许您替换任何方法,包括静态或非虚拟。 相当新的项目,但完全开源麻省理工学院许可证。 https://github.com/tonerdo/pose

正如@aqwert和@Felice在使用Typemock Isolator时所写的那样,在不添加或更改任何代码的情况下模拟非虚拟方法是可能的(并且非常简单),例如:

 [TestMethod,Isolated] public void TestMethod1() { var mock = Isolate.Fake.Instance(); Isolate.WhenCalled(() => mock.SendEmail()).WillReturn(true); var cust = new Customer(); var result = cust.AddCustomer(mock); Assert.IsTrue(result); } 

正如您所看到的,我创建的测试与您尝试创建的测试类似。

模拟非虚方法的唯一方法是模拟用于使用非虚方法实现该类的接口。 以下是示例。

 public interface IEmployee { DateTime GetDateofJoining(int id); } public class Employee { public DateTime GetDateofJoining(int id) { return DateTime.Now; } } public class Program { static void Main(string[] args) { var employee = new Mock(); employee.Setup(x => x.GetDateofJoining(It.IsAny())).Returns((int x) => DateTime.Now); Console.WriteLine(employee.Object.GetDateofJoining(1)); Console.ReadLine(); } }